Skip to content

Commit aebc43e

Browse files
committed
fine tuning
1 parent 2fd601d commit aebc43e

File tree

4 files changed

+69
-22
lines changed

4 files changed

+69
-22
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ Intersects() O(log(n))
2525
CoverLCP() O(log(n))
2626
CoverSCP() O(log(n))
2727
28-
Covers() O(k*log(n))
29-
CoveredBy() O(k*log(n))
30-
Precedes() O(k*log(n))
31-
PrecededBy() O(k*log(n))
32-
Intersections() O(k*log(n))
28+
Covers() O(k+log(n))
29+
CoveredBy() O(k+log(n))
30+
Precedes() O(k+log(n))
31+
PrecededBy() O(k+log(n))
32+
Intersections() O(k+log(n))
3333
```
3434

3535
The author is propably the first (in december 2022) using augmented treaps

comparer.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,9 @@ func (t *Tree[T]) cmpLR(a, b T) int {
135135
_, _, lr, _ := t.cmp(a, b)
136136
return lr
137137
}
138+
139+
// cmpRL, compares just the right point from a with left point from b.
140+
func (t *Tree[T]) cmpRL(a, b T) int {
141+
_, _, _, rl := t.cmp(a, b)
142+
return rl
143+
}

treap.go

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,14 @@ func (t *Tree[T]) lcp(n *node[T], item T) (result T, ok bool) {
372372

373373
switch cmp := t.compare(n.item, item); {
374374
case cmp > 0:
375-
// left rec-descent
375+
// too big, left rec-descent
376376
return t.lcp(n.left, item)
377377
case cmp == 0:
378378
// equality is always the shortest containing hull
379379
return n.item, true
380380
}
381381

382-
// right backtracking
382+
// LCP => right backtracking
383383
result, ok = t.lcp(n.right, item)
384384
if ok {
385385
return result, ok
@@ -452,7 +452,7 @@ func (t *Tree[T]) scp(n *node[T], item T) (result T, ok bool) {
452452
return
453453
}
454454

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

534534
// Intersects returns true if any interval intersects item.
535535
func (t Tree[T]) Intersects(item T) bool {
536-
return t.isects(t.root, item)
536+
return t.intersects(t.root, item)
537537
}
538538

539539
// intersects rec-descent
540-
func (t *Tree[T]) isects(n *node[T], item T) bool {
540+
func (t *Tree[T]) intersects(n *node[T], item T) bool {
541541
if n == nil {
542542
return false
543543
}
544544

545-
// nope, subtree has too small upper value for intersection
545+
// this n.item, fast exit
546+
if t.cmpIntersects(n.item, item) {
547+
return true
548+
}
549+
550+
// don't traverse this subtree, subtree has too small upper value for intersection
551+
// item -> |------|
552+
// |-------------| <- maxUpper
546553
if t.cmpLR(item, n.maxUpper.item) > 0 {
547554
return false
548555
}
549556

550557
// recursive call to left tree
551-
if t.isects(n.left, item) {
558+
// fast return if true
559+
if t.intersects(n.left, item) {
552560
return true
553561
}
554562

555-
// this n.item
556-
if t.cmpIntersects(n.item, item) {
557-
return true
563+
// don't traverse right subtree, subtree has too small left value for intersection.
564+
// |---------| <- item
565+
// n.item |-------------|
566+
if t.cmpRL(item, n.item) < 0 {
567+
return false
558568
}
559569

560570
// recursive call to right tree
561-
return t.isects(n.right, item)
571+
return t.intersects(n.right, item)
562572
}
563573

564574
// Intersections returns all intervals that intersect with item.
565575
// The returned intervals are in sorted order.
566576
func (t Tree[T]) Intersections(item T) []T {
567-
return t.isections(t.root, item)
577+
return t.intersections(t.root, item)
568578
}
569579

570-
// isections rec-descent
571-
func (t *Tree[T]) isections(n *node[T], item T) (result []T) {
580+
// intersections rec-descent
581+
func (t *Tree[T]) intersections(n *node[T], item T) (result []T) {
572582
if n == nil {
573583
return
574584
}
575585

576-
// nope, subtree has too small upper value for intersection
586+
// don't traverse this subtree, subtree has too small upper value for intersection
587+
// item -> |------|
588+
// |-------------| <- maxUpper
577589
if t.cmpLR(item, n.maxUpper.item) > 0 {
578590
return
579591
}
580592

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

584596
// this n.item
585597
if t.cmpIntersects(n.item, item) {
586598
result = append(result, n.item)
587599
}
588600

601+
// don't traverse right subtree, subtree has too small left value for intersection.
602+
// |---------| <- item
603+
// n.item |-------------|
604+
if t.cmpRL(item, n.item) < 0 {
605+
return
606+
}
607+
589608
// recursive call to right tree
590-
return append(result, t.isections(n.right, item)...)
609+
return append(result, t.intersections(n.right, item)...)
591610
}
592611

593612
// Precedes returns all intervals that precedes the item.

treap_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,28 @@ func TestIntersects(t *testing.T) {
560560
}
561561
}
562562

563+
func FuzzIntersects(f *testing.F) {
564+
ivals := genUintIvals(10_000)
565+
tree := interval.NewTree(cmpUintInterval, ivals...)
566+
567+
for i := 0; i < 10; i++ {
568+
a := ivals[i][0]
569+
b := ivals[i][1]
570+
f.Add(a, b)
571+
}
572+
573+
f.Fuzz(func(t *testing.T, a, b uint) {
574+
probe := makeUintIval(a, b)
575+
576+
gotBool := tree.Intersects(probe)
577+
gotSlice := tree.Intersections(probe)
578+
579+
if gotBool && gotSlice == nil || !gotBool && gotSlice != nil {
580+
t.Fatalf("Intersects(%v) and Intersections(%v) mismatch", probe, probe)
581+
}
582+
})
583+
}
584+
563585
func TestIntersections(t *testing.T) {
564586
t.Parallel()
565587

0 commit comments

Comments
 (0)