diff --git a/README.md b/README.md index 71cdc2d..69425f3 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ To apply this library to types of one-dimensional intervals, you must provide a import "github.com/gaissmai/interval" type Tree[T any] struct{ ... } - func NewTree[T any](cmp func(a, b T) (ll, rr, lr, rl int)) Tree[T] + func NewTree[T any](cmp func(a, b T) (ll, rr, lr, rl int), items ...T) Tree[T] func (t Tree[T]) Insert(items ...T) Tree[T] func (t Tree[T]) Delete(item T) (Tree[T], bool) diff --git a/bench_test.go b/bench_test.go index 1d33263..fb07c5d 100644 --- a/bench_test.go +++ b/bench_test.go @@ -17,11 +17,9 @@ var intMap = map[int]string{ 1_000_000: "1_000_000", } -var tree = interval.NewTree(compareIval) - func BenchmarkInsert(b *testing.B) { for n := 1; n <= 1_000_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "Into" + intMap[n] @@ -37,7 +35,7 @@ func BenchmarkInsert(b *testing.B) { func BenchmarkInsertMutable(b *testing.B) { for n := 1; n <= 1_000_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "Into" + intMap[n] @@ -55,7 +53,7 @@ func BenchmarkDelete(b *testing.B) { ivals := generateIvals(n) probe := ivals[rand.Intn(len(ivals))] - tree := tree.Insert(ivals...) + tree := interval.NewTree(compareIval, ivals...) name := "DeleteFrom" + intMap[n] b.Run(name, func(b *testing.B) { @@ -72,7 +70,7 @@ func BenchmarkDeleteMutable(b *testing.B) { ivals := generateIvals(n) probe := ivals[rand.Intn(len(ivals))] - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) name := "DeleteFrom" + intMap[n] b.Run(name, func(b *testing.B) { @@ -86,7 +84,7 @@ func BenchmarkDeleteMutable(b *testing.B) { func BenchmarkClone(b *testing.B) { for n := 10; n <= 10_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) name := intMap[n] b.Run(name, func(b *testing.B) { @@ -99,9 +97,9 @@ func BenchmarkClone(b *testing.B) { } func BenchmarkUnionImmutable(b *testing.B) { - this100_000 := tree.Insert(generateIvals(100_000)...) + this100_000 := interval.NewTree(compareIval, generateIvals(100_000)...) for n := 10; n <= 100_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) name := "size100_000with" + intMap[n] b.Run(name, func(b *testing.B) { @@ -115,8 +113,8 @@ func BenchmarkUnionImmutable(b *testing.B) { func BenchmarkUnionMutable(b *testing.B) { for n := 10; n <= 100_000; n *= 10 { - this100_000 := tree.Insert(generateIvals(100_000)...) - tree := tree.Insert(generateIvals(n)...) + this100_000 := interval.NewTree(compareIval, generateIvals(100_000)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) name := "size100_000with" + intMap[n] b.Run(name, func(b *testing.B) { @@ -131,7 +129,7 @@ func BenchmarkUnionMutable(b *testing.B) { func BenchmarkIntersects(b *testing.B) { for n := 1; n <= 1_000_000; n *= 10 { ivals := generateIvals(n) - tree := tree.Insert(ivals...) + tree := interval.NewTree(compareIval, ivals...) probe := ivals[rand.Intn(len(ivals))] name := "In" + intMap[n] @@ -147,7 +145,7 @@ func BenchmarkIntersects(b *testing.B) { func BenchmarkFind(b *testing.B) { for n := 1; n <= 1_000_000; n *= 10 { ivals := generateIvals(n) - tree := tree.Insert(ivals...) + tree := interval.NewTree(compareIval, ivals...) probe := ivals[rand.Intn(len(ivals))] name := "In" + intMap[n] @@ -162,7 +160,7 @@ func BenchmarkFind(b *testing.B) { func BenchmarkCoverLCP(b *testing.B) { for n := 100; n <= 1_000_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "In" + intMap[n] @@ -177,7 +175,7 @@ func BenchmarkCoverLCP(b *testing.B) { func BenchmarkCoverSCP(b *testing.B) { for n := 100; n <= 1_000_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "In" + intMap[n] @@ -192,7 +190,7 @@ func BenchmarkCoverSCP(b *testing.B) { func BenchmarkCoveredBy(b *testing.B) { for n := 100; n <= 100_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "In" + intMap[n] @@ -207,7 +205,7 @@ func BenchmarkCoveredBy(b *testing.B) { func BenchmarkCovers(b *testing.B) { for n := 100; n <= 100_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "In" + intMap[n] @@ -222,7 +220,7 @@ func BenchmarkCovers(b *testing.B) { func BenchmarkPrecededBy(b *testing.B) { for m := 100; m <= 10_000; m *= 10 { - tree := tree.Insert(generateIvals(m)...) + tree := interval.NewTree(compareIval, generateIvals(m)...) probe := generateIvals(1)[0] name := "In" + intMap[m] @@ -237,7 +235,7 @@ func BenchmarkPrecededBy(b *testing.B) { func BenchmarkPrecedes(b *testing.B) { for m := 100; m <= 10_000; m *= 10 { - tree := tree.Insert(generateIvals(m)...) + tree := interval.NewTree(compareIval, generateIvals(m)...) probe := generateIvals(1)[0] name := "In" + intMap[m] @@ -252,7 +250,7 @@ func BenchmarkPrecedes(b *testing.B) { func BenchmarkIntersections(b *testing.B) { for n := 100; n <= 10_000; n *= 10 { - tree := tree.Insert(generateIvals(n)...) + tree := interval.NewTree(compareIval, generateIvals(n)...) probe := generateIvals(1)[0] name := "In" + intMap[n] @@ -268,7 +266,7 @@ func BenchmarkIntersections(b *testing.B) { func BenchmarkMin(b *testing.B) { for n := 100; n <= 1_000_000; n *= 10 { ivals := generateIvals(n) - tree := tree.Insert(ivals...) + tree := interval.NewTree(compareIval, ivals...) name := "In" + intMap[n] b.Run(name, func(b *testing.B) { @@ -283,7 +281,7 @@ func BenchmarkMin(b *testing.B) { func BenchmarkMax(b *testing.B) { for n := 100; n <= 1_000_000; n *= 10 { ivals := generateIvals(n) - tree := tree.Insert(ivals...) + tree := interval.NewTree(compareIval, ivals...) name := "In" + intMap[n] b.Run(name, func(b *testing.B) { diff --git a/example_period_test.go b/example_period_test.go index 85b8a29..8a3eda8 100644 --- a/example_period_test.go +++ b/example_period_test.go @@ -40,8 +40,7 @@ func compareIval(p, q Ival) (ll, rr, lr, rl int) { } func ExampleNewTree() { - tree1 := interval.NewTree(compareIval) - tree1.InsertMutable(periods...) + tree1 := interval.NewTree(compareIval, periods...) tree1.Fprint(os.Stdout) // Output: @@ -53,7 +52,7 @@ func ExampleNewTree() { } func ExampleTree_Max() { - tree1 := tree.Insert(periods...) + tree1 := interval.NewTree(compareIval, periods...) tree1.Fprint(os.Stdout) fmt.Println("\nInterval with max value in tree:") @@ -71,7 +70,7 @@ func ExampleTree_Max() { } func ExampleTree_Covers() { - tree1 := tree.Insert(periods...) + tree1 := interval.NewTree(compareIval, periods...) tree1.Fprint(os.Stdout) item := Ival{3, 4} @@ -94,7 +93,7 @@ func ExampleTree_Covers() { } func ExampleTree_CoveredBy() { - tree1 := tree.Insert(periods...) + tree1 := interval.NewTree(compareIval, periods...) tree1.Fprint(os.Stdout) item := Ival{3, 10} @@ -117,7 +116,7 @@ func ExampleTree_CoveredBy() { } func ExampleTree_Precedes_period() { - tree1 := tree.Insert(periods...) + tree1 := interval.NewTree(compareIval, periods...) tree1.Fprint(os.Stdout) item := Ival{6, 6} @@ -139,7 +138,7 @@ func ExampleTree_Precedes_period() { } func ExampleTree_Visit() { - tree1 := tree.Insert(periods...) + tree1 := interval.NewTree(compareIval, periods...) fmt.Println("parent/child printing") tree1.Fprint(os.Stdout) diff --git a/example_time_test.go b/example_time_test.go index 02e2d91..809cb17 100644 --- a/example_time_test.go +++ b/example_time_test.go @@ -47,8 +47,6 @@ func compareTval(p, q Tval) (ll, rr, lr, rl int) { cmpTime(p.death, q.birth) } -var timeTree = interval.NewTree(compareTval) - // example data var physicists = []Tval{ mkTval(1473, 1543, "Kopernikus"), @@ -82,11 +80,11 @@ var physicists = []Tval{ } func ExampleTree_Precedes_time() { - tree := timeTree.Insert(physicists...) + tree := interval.NewTree(compareTval, physicists...) tree.Fprint(os.Stdout) precedes := tree.Precedes(mkTval(1643, 1727, "Newton")) - tree = timeTree.Insert(precedes...) + tree = interval.NewTree(compareTval, precedes...) fmt.Println("\nPrecedes Newton:") tree.Fprint(os.Stdout) @@ -131,11 +129,11 @@ func ExampleTree_Precedes_time() { } func ExampleTree_PrecededBy_time() { - tree := timeTree.Insert(physicists...) + tree := interval.NewTree(compareTval, physicists...) tree.Fprint(os.Stdout) precededBy := tree.PrecededBy(mkTval(1643, 1727, "Newton")) - tree = timeTree.Insert(precededBy...) + tree = interval.NewTree(compareTval, precededBy...) fmt.Println("\nPrecededBy Newton:") tree.Fprint(os.Stdout) diff --git a/treap.go b/treap.go index 27d38f4..8da20c2 100644 --- a/treap.go +++ b/treap.go @@ -32,7 +32,7 @@ type Tree[T any] struct { cmp func(T, T) (ll, rr, lr, rl int) } -// NewTree initializes the interval tree with the interval comparison function for type T. +// NewTree initializes the interval tree with the compare function and items from type T. // // cmp(a, b T) (ll, rr, lr, rl int) // @@ -43,9 +43,15 @@ type Tree[T any] struct { // lr: left point interval a compared with right point interval b (-1, 0, +1) // rl: right point interval a compared with left point interval b (-1, 0, +1) // -func NewTree[T any](cmp func(a, b T) (ll, rr, lr, rl int)) Tree[T] { +func NewTree[T any](cmp func(a, b T) (ll, rr, lr, rl int), items ...T) Tree[T] { var t Tree[T] t.cmp = cmp + + // mutable insert + for i := range items { + t.root = t.root.insert(t.makeNode(items[i]), false, &t) + } + return t } diff --git a/treap_test.go b/treap_test.go index 4c78274..13efe76 100644 --- a/treap_test.go +++ b/treap_test.go @@ -173,7 +173,7 @@ func TestTreeWithDups(t *testing.T) { {3, 13}, } - tree1 := tree.Insert(is...) + tree1 := interval.NewTree(compareIval, is...) if size, _, _, _ := tree1.Statistics(); size != 5 { t.Errorf("Size() = %v, want 5", size) } @@ -192,7 +192,7 @@ func TestTreeWithDups(t *testing.T) { func TestImmutable(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) if _, ok := tree1.Delete(tree1.Min()); !ok { t.Fatal("Delete, could not delete min item") @@ -210,7 +210,7 @@ func TestImmutable(t *testing.T) { } func TestMutable(t *testing.T) { - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) clone := tree1.Clone() if !equalStatistics(tree1, clone) { @@ -233,7 +233,7 @@ func TestMutable(t *testing.T) { } // reset - tree1 = tree.Insert(ps...) + tree1 = interval.NewTree(compareIval, ps...) clone = tree1.Clone() if !equalStatistics(tree1, clone) { @@ -252,7 +252,7 @@ func TestFind(t *testing.T) { t.Parallel() ivals := generateIvals(100_00) - tree1 := tree.Insert(ivals...) + tree1 := interval.NewTree(compareIval, ivals...) for _, ival := range ivals { item, ok := tree1.Find(ival) @@ -271,7 +271,7 @@ func TestLookup(t *testing.T) { for i := 0; i < 100; i++ { // bring some variance into the Treap due to the prio randomness - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) // ▼ // ├─ 0...6 @@ -348,7 +348,7 @@ func TestLookup(t *testing.T) { func TestCoveredBy(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var want []Ival // ▼ @@ -394,7 +394,7 @@ func TestCoveredBy(t *testing.T) { func TestCovers(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var want []Ival // ▼ @@ -440,7 +440,7 @@ func TestCovers(t *testing.T) { func TestIntersects(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) // ▼ // ├─ 0...6 @@ -491,7 +491,7 @@ func TestIntersects(t *testing.T) { func TestIntersections(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var want []Ival // ▼ @@ -537,7 +537,7 @@ func TestIntersections(t *testing.T) { func TestPrecedes(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var want []Ival // ▼ @@ -583,7 +583,7 @@ func TestPrecedes(t *testing.T) { func TestPrecededBy(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var want []Ival // ▼ @@ -628,7 +628,7 @@ func TestPrecededBy(t *testing.T) { func TestVisit(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) var collect []Ival want := 4 @@ -663,7 +663,7 @@ func TestVisit(t *testing.T) { func TestMinMax(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) want := Ival{0, 6} if tree1.Min() != want { t.Fatalf("Min(), want: %v, got: %v", want, tree1.Min()) @@ -677,7 +677,7 @@ func TestMinMax(t *testing.T) { func TestUnion(t *testing.T) { t.Parallel() - tree1 := tree.Insert() + tree1 := interval.NewTree(compareIval) for i := range ps { b := tree1.Insert(ps[i]) @@ -760,7 +760,7 @@ func TestStatistics(t *testing.T) { for n := 10_000; n <= 1_000_000; n *= 10 { count := strconv.Itoa(n) t.Run(count, func(t *testing.T) { - tree1 := tree.Insert(generateIvals(n)...) + tree1 := interval.NewTree(compareIval, generateIvals(n)...) size, _, averageDepth, deviation := tree1.Statistics() if size != n { @@ -784,7 +784,7 @@ func TestStatistics(t *testing.T) { func TestPrintBST(t *testing.T) { t.Parallel() - tree1 := tree.Insert(ps...) + tree1 := interval.NewTree(compareIval, ps...) w := new(strings.Builder) _ = tree1.FprintBST(w) @@ -798,7 +798,7 @@ func TestPrintBST(t *testing.T) { func TestMatch(t *testing.T) { t.Parallel() - tree1 := tree.Insert(generateIvals(100_000)...) + tree1 := interval.NewTree(compareIval, generateIvals(100_000)...) n := 100 for i := 0; i < n; i++ { @@ -849,7 +849,7 @@ func TestMatch(t *testing.T) { func TestMissing(t *testing.T) { t.Parallel() - tree1 := tree.Insert(generateIvals(100_000)...) + tree1 := interval.NewTree(compareIval, generateIvals(100_000)...) n := 100 for i := 0; i < n; i++ {