diff --git a/trees/avl/LICENSE b/trees/avltree/LICENSE similarity index 100% rename from trees/avl/LICENSE rename to trees/avltree/LICENSE diff --git a/trees/avl/avl.go b/trees/avltree/avltree.go similarity index 84% rename from trees/avl/avl.go rename to trees/avltree/avltree.go index 09b5181..226efcc 100644 --- a/trees/avl/avl.go +++ b/trees/avltree/avltree.go @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package avl implements an AVL balanced binary tree. +// Package avltree implements an AVL balanced binary tree. // // Structure is not thread safe. -// -package avl +package avltree import ( + "fmt" "io/ioutil" "log" @@ -20,7 +20,7 @@ func assertTreeImplementation() { var _ trees.Tree = new(Tree) } -var dbgLog = log.New(ioutil.Discard, "avl: ", log.LstdFlags) +var dbgLog = log.New(ioutil.Discard, "avltree: ", log.LstdFlags) // Tree holds elements of the AVL tree. type Tree struct { @@ -29,8 +29,7 @@ type Tree struct { Comparator utils.Comparator } -// A Node holds an Ordered element of the AVL tree in -// the Val field. +// Node is a single element within the tree type Node struct { Key interface{} Value interface{} @@ -70,20 +69,18 @@ func (t *Tree) Clear() { t.size = 0 } -// Get looks up val and returns the matching element if -// it is found. -// -// Val's Less implementation must be able to handle -// comparisons to elements stored in this tree. +// Get searches the node in the tree by key and returns its value or nil if key is not found in tree. +// Second return parameter is true if key was found, otherwise false. +// Key should adhere to the comparator's type assertion, otherwise method panics. func (t *Tree) Get(key interface{}) (value interface{}, found bool) { n := t.Root for n != nil { cmp := t.Comparator(key, n.Key) switch { - case cmp < 0: - n = n.c[0] case cmp == 0: return n.Value, true + case cmp < 0: + n = n.c[0] case cmp > 0: n = n.c[1] } @@ -205,7 +202,7 @@ func (t *Tree) Remove(key interface{}) { *qp = q.c[0] return true } - fix := removemin(&q.c[1], &q.Key, &q.Value) + fix := removeMin(&q.c[1], &q.Key, &q.Value) if fix { return removeFix(-1, qp) } @@ -228,7 +225,7 @@ func (t *Tree) Remove(key interface{}) { remove(&t.Root) } -func removemin(qp **Node, minKey *interface{}, minVal *interface{}) bool { +func removeMin(qp **Node, minKey *interface{}, minVal *interface{}) bool { q := *qp if q.c[0] == nil { *minKey = q.Key @@ -239,7 +236,7 @@ func removemin(qp **Node, minKey *interface{}, minVal *interface{}) bool { *qp = q.c[1] return true } - fix := removemin(&q.c[0], minKey, minVal) + fix := removeMin(&q.c[0], minKey, minVal) if fix { return removeFix(1, qp) } @@ -423,3 +420,44 @@ func (n *Node) walk1(a int) *Node { } return p } + +// String returns a string representation of container +func (t *Tree) String() string { + str := "AVLTree\n" + if !t.Empty() { + output(t.Root, "", true, &str) + } + return str +} + +func (n *Node) String() string { + return fmt.Sprintf("%v", n.Key) +} + +func output(node *Node, prefix string, isTail bool, str *string) { + if node.c[0] != nil { + newPrefix := prefix + if isTail { + newPrefix += "│ " + } else { + newPrefix += " " + } + output(node.c[0], newPrefix, false, str) + } + *str += prefix + if isTail { + *str += "└── " + } else { + *str += "┌── " + } + *str += node.String() + "\n" + if node.c[1] != nil { + newPrefix := prefix + if isTail { + newPrefix += " " + } else { + newPrefix += "│ " + } + output(node.c[1], newPrefix, true, str) + } +} diff --git a/trees/avl/avl_test.go b/trees/avltree/avltree_test.go similarity index 82% rename from trees/avl/avl_test.go rename to trees/avltree/avltree_test.go index 94db9e4..f79b739 100644 --- a/trees/avl/avl_test.go +++ b/trees/avltree/avltree_test.go @@ -2,13 +2,24 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package avl +package avltree import ( "fmt" + "math/rand" + "os" "testing" + "time" ) +var rng *rand.Rand + +func TestMain(m *testing.M) { + seed := time.Now().UTC().UnixNano() + rng = rand.New(rand.NewSource(seed)) + os.Exit(m.Run()) +} + func TestAVLPut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") @@ -557,7 +568,15 @@ func TestAVLIteratorLast(t *testing.T) { } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func newRandomIntTree(size, randMax int) *Tree { + tree := NewWithIntComparator() + for i := 0; i < size; i++ { + tree.Put(rng.Intn(randMax), nil) + } + return tree +} + +func (tree *Tree) benchmarkGet(b *testing.B, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -565,19 +584,53 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Get(rng.Intn(randMax)) + } + } +} + +func (tree *Tree) benchmarkPut(b *testing.B, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(rng.Intn(randMax), nil) } + tree.Empty() } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } for n := 0; n < size; n++ { tree.Remove(n) } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(rng.Intn(randMax), nil) + } + for n := 0; n < size; n++ { + tree.Remove(rng.Intn(randMax)) + } + tree.Empty() } } @@ -586,10 +639,10 @@ func BenchmarkAVLGet100(b *testing.B) { size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet1000(b *testing.B) { @@ -597,10 +650,10 @@ func BenchmarkAVLGet1000(b *testing.B) { size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet10000(b *testing.B) { @@ -608,10 +661,10 @@ func BenchmarkAVLGet10000(b *testing.B) { size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } func BenchmarkAVLGet100000(b *testing.B) { @@ -619,18 +672,53 @@ func BenchmarkAVLGet100000(b *testing.B) { size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) +} + +func BenchmarkAVLGetRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) } func BenchmarkAVLPut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, nil) + } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut1000(b *testing.B) { @@ -638,10 +726,10 @@ func BenchmarkAVLPut1000(b *testing.B) { size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut10000(b *testing.B) { @@ -649,10 +737,10 @@ func BenchmarkAVLPut10000(b *testing.B) { size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } func BenchmarkAVLPut100000(b *testing.B) { @@ -660,52 +748,84 @@ func BenchmarkAVLPut100000(b *testing.B) { size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) +} + +func BenchmarkAVLPutRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) } -func BenchmarkAVLRemove100(b *testing.B) { +func BenchmarkAVLPutAndRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove1000(b *testing.B) { +func BenchmarkAVLPutAndRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove10000(b *testing.B) { +func BenchmarkAVLPutAndRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkAVLRemove100000(b *testing.B) { +func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } diff --git a/trees/avl/iterator.go b/trees/avltree/iterator.go similarity index 99% rename from trees/avl/iterator.go rename to trees/avltree/iterator.go index b2df5c6..a3d930c 100644 --- a/trees/avl/iterator.go +++ b/trees/avltree/iterator.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package avl +package avltree import "github.com/emirpasic/gods/containers" diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go index 714defc..bca5e7e 100644 --- a/trees/redblacktree/redblacktree_test.go +++ b/trees/redblacktree/redblacktree_test.go @@ -6,9 +6,20 @@ package redblacktree import ( "fmt" + "math/rand" + "os" "testing" + "time" ) +var rng *rand.Rand + +func TestMain(m *testing.M) { + seed := time.Now().UTC().UnixNano() + rng = rand.New(rand.NewSource(seed)) + os.Exit(m.Run()) +} + func TestRedBlackTreePut(t *testing.T) { tree := NewWithIntComparator() tree.Put(5, "e") @@ -19,7 +30,7 @@ func TestRedBlackTreePut(t *testing.T) { tree.Put(1, "x") tree.Put(2, "b") tree.Put(1, "a") //overwrite - + t.Log(tree) if actualValue := tree.Size(); actualValue != 7 { t.Errorf("Got %v expected %v", actualValue, 7) } @@ -557,7 +568,15 @@ func TestRedBlackTreeIteratorLast(t *testing.T) { } } -func benchmarkGet(b *testing.B, tree *Tree, size int) { +func newRandomIntTree(size, randMax int) *Tree { + tree := NewWithIntComparator() + for i := 0; i < size; i++ { + tree.Put(rng.Intn(randMax), nil) + } + return tree +} + +func (tree *Tree) benchmarkGet(b *testing.B, size int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { tree.Get(n) @@ -565,147 +584,248 @@ func benchmarkGet(b *testing.B, tree *Tree, size int) { } } -func benchmarkPut(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkGetRandom(b *testing.B, size, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Get(rng.Intn(randMax)) + } + } +} + +func (tree *Tree) benchmarkPut(b *testing.B, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutRandom(b *testing.B, size, randMax int) { for i := 0; i < b.N; i++ { for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(rng.Intn(randMax), nil) } + tree.Empty() } } -func benchmarkRemove(b *testing.B, tree *Tree, size int) { +func (tree *Tree) benchmarkPutAndRemove(b *testing.B, size int) { for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(n, nil) + } for n := 0; n < size; n++ { tree.Remove(n) } + tree.Empty() + } +} + +func (tree *Tree) benchmarkPutAndRemoveRandom(b *testing.B, size int, randMax int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + tree.Put(rng.Intn(randMax), nil) + } + for n := 0; n < size; n++ { + tree.Remove(rng.Intn(randMax)) + } + tree.Empty() } } -func BenchmarkRedBlackTreeGet100(b *testing.B) { +func BenchmarkAVLGet100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet1000(b *testing.B) { +func BenchmarkAVLGet1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet10000(b *testing.B) { +func BenchmarkAVLGet10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) } -func BenchmarkRedBlackTreeGet100000(b *testing.B) { +func BenchmarkAVLGet100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkGet(b, tree, size) + tree.benchmarkGet(b, size) +} + +func BenchmarkAVLGetRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLGetRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) } -func BenchmarkRedBlackTreePut100(b *testing.B) { +func BenchmarkAVLGetRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkGetRandom(b, size, size*5) +} + +func BenchmarkAVLPut100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() + for n := 0; n < size; n++ { + tree.Put(n, nil) + } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut1000(b *testing.B) { +func BenchmarkAVLPut1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut10000(b *testing.B) { +func BenchmarkAVLPut10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) } -func BenchmarkRedBlackTreePut100000(b *testing.B) { +func BenchmarkAVLPut100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkPut(b, tree, size) + tree.benchmarkPut(b, size) +} + +func BenchmarkAVLPutRandom100(b *testing.B) { + b.StopTimer() + size := 100 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom1000(b *testing.B) { + b.StopTimer() + size := 1000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom10000(b *testing.B) { + b.StopTimer() + size := 10000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) +} + +func BenchmarkAVLPutRandom100000(b *testing.B) { + b.StopTimer() + size := 100000 + tree := newRandomIntTree(size, size*5) + b.StartTimer() + tree.benchmarkPutRandom(b, size, size*5) } -func BenchmarkRedBlackTreeRemove100(b *testing.B) { +func BenchmarkAVLPutAndRemove100(b *testing.B) { b.StopTimer() size := 100 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove1000(b *testing.B) { +func BenchmarkAVLPutAndRemove1000(b *testing.B) { b.StopTimer() size := 1000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove10000(b *testing.B) { +func BenchmarkAVLPutAndRemove10000(b *testing.B) { b.StopTimer() size := 10000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) } -func BenchmarkRedBlackTreeRemove100000(b *testing.B) { +func BenchmarkAVLPutAndRemove100000(b *testing.B) { b.StopTimer() size := 100000 tree := NewWithIntComparator() for n := 0; n < size; n++ { - tree.Put(n, struct{}{}) + tree.Put(n, nil) } b.StartTimer() - benchmarkRemove(b, tree, size) + tree.benchmarkPutAndRemove(b, size) }