Skip to content

Commit

Permalink
fine tuning
Browse files Browse the repository at this point in the history
  • Loading branch information
gaissmai committed Jan 28, 2023
1 parent 2fd601d commit aebc43e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 22 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ Intersects() O(log(n))
CoverLCP() O(log(n))
CoverSCP() O(log(n))
Covers() O(k*log(n))
CoveredBy() O(k*log(n))
Precedes() O(k*log(n))
PrecededBy() O(k*log(n))
Intersections() O(k*log(n))
Covers() O(k+log(n))
CoveredBy() O(k+log(n))
Precedes() O(k+log(n))
PrecededBy() O(k+log(n))
Intersections() O(k+log(n))
```

The author is propably the first (in december 2022) using augmented treaps
Expand Down
6 changes: 6 additions & 0 deletions comparer.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,9 @@ func (t *Tree[T]) cmpLR(a, b T) int {
_, _, lr, _ := t.cmp(a, b)
return lr
}

// cmpRL, compares just the right point from a with left point from b.
func (t *Tree[T]) cmpRL(a, b T) int {
_, _, _, rl := t.cmp(a, b)
return rl
}
53 changes: 36 additions & 17 deletions treap.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,14 +372,14 @@ func (t *Tree[T]) lcp(n *node[T], item T) (result T, ok bool) {

switch cmp := t.compare(n.item, item); {
case cmp > 0:
// left rec-descent
// too big, left rec-descent
return t.lcp(n.left, item)
case cmp == 0:
// equality is always the shortest containing hull
return n.item, true
}

// right backtracking
// LCP => right backtracking
result, ok = t.lcp(n.right, item)
if ok {
return result, ok
Expand Down Expand Up @@ -452,7 +452,7 @@ func (t *Tree[T]) scp(n *node[T], item T) (result T, ok bool) {
return
}

// left backtracking
// SCP => left backtracking
if result, ok = t.scp(n.left, item); ok {
return result, ok
}
Expand Down Expand Up @@ -533,61 +533,80 @@ func (t *Tree[T]) coveredBy(n *node[T], item T) (result []T) {

// Intersects returns true if any interval intersects item.
func (t Tree[T]) Intersects(item T) bool {
return t.isects(t.root, item)
return t.intersects(t.root, item)
}

// intersects rec-descent
func (t *Tree[T]) isects(n *node[T], item T) bool {
func (t *Tree[T]) intersects(n *node[T], item T) bool {
if n == nil {
return false
}

// nope, subtree has too small upper value for intersection
// this n.item, fast exit
if t.cmpIntersects(n.item, item) {
return true
}

// don't traverse this subtree, subtree has too small upper value for intersection
// item -> |------|
// |-------------| <- maxUpper
if t.cmpLR(item, n.maxUpper.item) > 0 {
return false
}

// recursive call to left tree
if t.isects(n.left, item) {
// fast return if true
if t.intersects(n.left, item) {
return true
}

// this n.item
if t.cmpIntersects(n.item, item) {
return true
// don't traverse right subtree, subtree has too small left value for intersection.
// |---------| <- item
// n.item |-------------|
if t.cmpRL(item, n.item) < 0 {
return false
}

// recursive call to right tree
return t.isects(n.right, item)
return t.intersects(n.right, item)
}

// Intersections returns all intervals that intersect with item.
// The returned intervals are in sorted order.
func (t Tree[T]) Intersections(item T) []T {
return t.isections(t.root, item)
return t.intersections(t.root, item)
}

// isections rec-descent
func (t *Tree[T]) isections(n *node[T], item T) (result []T) {
// intersections rec-descent
func (t *Tree[T]) intersections(n *node[T], item T) (result []T) {
if n == nil {
return
}

// nope, subtree has too small upper value for intersection
// don't traverse this subtree, subtree has too small upper value for intersection
// item -> |------|
// |-------------| <- maxUpper
if t.cmpLR(item, n.maxUpper.item) > 0 {
return
}

// in-order traversal for intersections, recursive call to left tree
result = append(result, t.isections(n.left, item)...)
result = append(result, t.intersections(n.left, item)...)

// this n.item
if t.cmpIntersects(n.item, item) {
result = append(result, n.item)
}

// don't traverse right subtree, subtree has too small left value for intersection.
// |---------| <- item
// n.item |-------------|
if t.cmpRL(item, n.item) < 0 {
return
}

// recursive call to right tree
return append(result, t.isections(n.right, item)...)
return append(result, t.intersections(n.right, item)...)
}

// Precedes returns all intervals that precedes the item.
Expand Down
22 changes: 22 additions & 0 deletions treap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,28 @@ func TestIntersects(t *testing.T) {
}
}

func FuzzIntersects(f *testing.F) {
ivals := genUintIvals(10_000)
tree := interval.NewTree(cmpUintInterval, ivals...)

for i := 0; i < 10; i++ {
a := ivals[i][0]
b := ivals[i][1]
f.Add(a, b)
}

f.Fuzz(func(t *testing.T, a, b uint) {
probe := makeUintIval(a, b)

gotBool := tree.Intersects(probe)
gotSlice := tree.Intersections(probe)

if gotBool && gotSlice == nil || !gotBool && gotSlice != nil {
t.Fatalf("Intersects(%v) and Intersections(%v) mismatch", probe, probe)
}
})
}

func TestIntersections(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit aebc43e

Please sign in to comment.