diff --git a/README.md b/README.md
index 5095c624..0ebd8ebf 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ Implementation of various data structures and algorithms in Go.
- [TreeBidiMap](#treebidimap)
- [Trees](#trees)
- [RedBlackTree](#redblacktree)
+ - [BTree](#btree)
- [BinaryHeap](#binaryheap)
- [Functions](#functions)
- [Comparator](#comparator)
@@ -69,6 +70,7 @@ Containers are either ordered or unordered. All ordered containers provide [stat
| [HashBidiMap](#hashbidimap) | no | no | no | key* |
| [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* |
| [RedBlackTree](#redblacktree) | yes | yes* | no | key |
+| [BTree](#btree) | yes | yes* | no | key |
| [BinaryHeap](#binaryheap) | yes | yes* | no | index |
| | | *reversible | | *bidirectional |
@@ -525,11 +527,11 @@ type Tree interface {
A red–black [tree](#trees) is a binary search tree with an extra bit of data per node, its color, which can be either red or black. The extra bit of storage ensures an approximately balanced tree by constraining how nodes are colored from any path from the root to the leaf. Thus, it is a data structure which is a type of self-balancing binary search tree.
-The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
+The balancing of the tree is not perfect but it is good enough to allow it to guarantee searching in O(log n) time, where n is the total number of elements in the tree. The insertion and deletion operations, along with the tree rearrangement and recoloring, are also performed in O(log n) time. [Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
-Implements [Tree](#trees) and [IteratorWithKey](#iteratorwithkey) interfaces.
+Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces.
-
+
```go
package main
@@ -550,7 +552,7 @@ func main() {
tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order)
tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order)
- fmt.Println(m)
+ fmt.Println(tree)
//
// RedBlackTree
// │ ┌── 6
@@ -564,7 +566,7 @@ func main() {
_ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6} (in order)
tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order)
- fmt.Println(m)
+ fmt.Println(tree)
//
// RedBlackTree
// │ ┌── 6
@@ -587,6 +589,81 @@ func main() {
Extending the red-black tree's functionality has been demonstrated in the following [example](https://github.com/emirpasic/gods/blob/master/examples/redblacktreeextended.go).
+#### BTree
+
+B-tree is a self-balancing tree data structure that keeps data sorted and allows searches, sequential access, insertions, and deletions in logarithmic time. The B-tree is a generalization of a binary search tree in that a node can have more than two children.
+
+According to Knuth's definition, a B-tree of order m is a tree which satisfies the following properties:
+
+- Every node has at most m children.
+- Every non-leaf node (except root) has at least ⌈m/2⌉ children.
+- The root has at least two children if it is not a leaf node.
+- A non-leaf node with k children contains k−1 keys.
+- All leaves appear in the same level
+
+Each internal node’s keys act as separation values which divide its subtrees. For example, if an internal node has 3 child nodes (or subtrees) then it must have 2 keys: a1 and a2. All values in the leftmost subtree will be less than a1, all values in the middle subtree will be between a1 and a2, and all values in the rightmost subtree will be greater than a2.[Wikipedia](http://en.wikipedia.org/wiki/Red%E2%80%93black_tree)
+
+Implements [Tree](#trees) and [ReverseIteratorWithKey](#reverseiteratorwithkey) interfaces.
+
+
+
+```go
+package main
+
+import (
+ "fmt"
+ "github.com/emirpasic/gods/trees/btree"
+)
+
+func main() {
+ tree := btree.NewWithIntComparator(3) // empty (keys are of type int)
+
+ tree.Put(1, "x") // 1->x
+ tree.Put(2, "b") // 1->x, 2->b (in order)
+ tree.Put(1, "a") // 1->a, 2->b (in order, replacement)
+ tree.Put(3, "c") // 1->a, 2->b, 3->c (in order)
+ tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order)
+ tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order)
+ tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order)
+ tree.Put(7, "g") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f, 7->g (in order)
+
+ fmt.Println(tree)
+ // BTree
+ // 1
+ // 2
+ // 3
+ // 4
+ // 5
+ // 6
+ // 7
+
+ _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f", "g"} (in order)
+ _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6, 7} (in order)
+
+ tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order)
+ fmt.Println(tree)
+ // BTree
+ // 1
+ // 3
+ // 4
+ // 5
+ // 6
+
+ tree.Clear() // empty
+ tree.Empty() // true
+ tree.Size() // 0
+
+ // Other:
+ tree.Height() // gets the height of the tree
+ tree.Left() // gets the left-most (min) node
+ tree.LeftKey() // get the left-most (min) node's key
+ tree.LeftValue() // get the left-most (min) node's value
+ tree.Right() // get the right-most (max) node
+ tree.RightKey() // get the right-most (max) node's key
+ tree.RightValue() // get the right-most (max) node's value
+}
+```
+
#### BinaryHeap
A binary heap is a [tree](#trees) created using a binary tree. It can be seen as a binary tree with two additional constraints:
@@ -596,11 +673,11 @@ A binary heap is a [tree](#trees) created using a binary tree. It can be seen as
A binary heap is a complete binary tree; that is, all levels of the tree, except possibly the last one (deepest) are fully filled, and, if the last level of the tree is not complete, the nodes of that level are filled from left to right.
- Heap property:
- All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap)
+ All nodes are either greater than or equal to or less than or equal to each of its children, according to a comparison predicate defined for the heap. [Wikipedia](http://en.wikipedia.org/wiki/Binary_heap)
-Implements [Tree](#trees) and [IteratorWithIndex](#iteratorwithindex) interfaces.
+Implements [Tree](#trees) and [ReverseIteratorWithIndex](#reverseiteratorwithindex) interfaces.
-
+
```go
package main
@@ -1142,7 +1219,11 @@ Thread safety is not a concern of this project, this should be handled at a high
### Testing and Benchmarking
-`go test -v -bench . -benchmem -benchtime 1s ./...`
+This takes a while, so test within sub-packages:
+
+`go test -run=NO_TEST -bench . -benchmem -benchtime 1s ./...`
+
+
### Contributing
diff --git a/examples/btree.go b/examples/btree.go
new file mode 100644
index 00000000..b9076965
--- /dev/null
+++ b/examples/btree.go
@@ -0,0 +1,59 @@
+// Copyright (c) 2015, Emir Pasic. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package examples
+
+import (
+ "fmt"
+ "github.com/emirpasic/gods/trees/btree"
+)
+
+// BTreeExample to demonstrate basic usage of BTree
+func BTreeExample() {
+ tree := btree.NewWithIntComparator(3) // empty (keys are of type int)
+
+ tree.Put(1, "x") // 1->x
+ tree.Put(2, "b") // 1->x, 2->b (in order)
+ tree.Put(1, "a") // 1->a, 2->b (in order, replacement)
+ tree.Put(3, "c") // 1->a, 2->b, 3->c (in order)
+ tree.Put(4, "d") // 1->a, 2->b, 3->c, 4->d (in order)
+ tree.Put(5, "e") // 1->a, 2->b, 3->c, 4->d, 5->e (in order)
+ tree.Put(6, "f") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f (in order)
+ tree.Put(7, "g") // 1->a, 2->b, 3->c, 4->d, 5->e, 6->f, 7->g (in order)
+
+ fmt.Println(tree)
+ // BTree
+ // 1
+ // 2
+ // 3
+ // 4
+ // 5
+ // 6
+ // 7
+
+ _ = tree.Values() // []interface {}{"a", "b", "c", "d", "e", "f", "g"} (in order)
+ _ = tree.Keys() // []interface {}{1, 2, 3, 4, 5, 6, 7} (in order)
+
+ tree.Remove(2) // 1->a, 3->c, 4->d, 5->e, 6->f (in order)
+ fmt.Println(tree)
+ // BTree
+ // 1
+ // 3
+ // 4
+ // 5
+ // 6
+
+ tree.Clear() // empty
+ tree.Empty() // true
+ tree.Size() // 0
+
+ // Other:
+ tree.Height() // gets the height of the tree
+ tree.Left() // gets the left-most (min) node
+ tree.LeftKey() // get the left-most (min) node's key
+ tree.LeftValue() // get the left-most (min) node's value
+ tree.Right() // get the right-most (max) node
+ tree.RightKey() // get the right-most (max) node's key
+ tree.RightValue() // get the right-most (max) node's value
+}
diff --git a/lists/arraylist/arraylist_test.go b/lists/arraylist/arraylist_test.go
index 8f70385e..67317e06 100644
--- a/lists/arraylist/arraylist_test.go
+++ b/lists/arraylist/arraylist_test.go
@@ -426,14 +426,155 @@ func TestListIteratorLast(t *testing.T) {
}
}
-func BenchmarkList(b *testing.B) {
+func benchmarkGet(b *testing.B, list *List, size int) {
for i := 0; i < b.N; i++ {
- list := New()
- for n := 0; n < 1000; n++ {
- list.Add(i)
+ for n := 0; n < size; n++ {
+ list.Get(n)
}
- for !list.Empty() {
- list.Remove(0)
+ }
+}
+
+func benchmarkAdd(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Remove(n)
}
}
}
+
+func BenchmarkArrayListGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkArrayListGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkArrayListGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkArrayListGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkArrayListAdd100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkArrayListAdd1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkArrayListAdd10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkArrayListAdd100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkArrayListRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkArrayListRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkArrayListRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkArrayListRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
diff --git a/lists/doublylinkedlist/doublylinkedlist_test.go b/lists/doublylinkedlist/doublylinkedlist_test.go
index 159761dc..fa663445 100644
--- a/lists/doublylinkedlist/doublylinkedlist_test.go
+++ b/lists/doublylinkedlist/doublylinkedlist_test.go
@@ -426,14 +426,155 @@ func TestListIteratorLast(t *testing.T) {
}
}
-func BenchmarkList(b *testing.B) {
+func benchmarkGet(b *testing.B, list *List, size int) {
for i := 0; i < b.N; i++ {
- list := New()
- for n := 0; n < 1000; n++ {
- list.Add(i)
+ for n := 0; n < size; n++ {
+ list.Get(n)
}
- for !list.Empty() {
- list.Remove(0)
+ }
+}
+
+func benchmarkAdd(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Remove(n)
}
}
}
+
+func BenchmarkDoublyLinkedListGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListAdd100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListAdd1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListAdd10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListAdd100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkDoublyLinkedListRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
diff --git a/lists/singlylinkedlist/singlylinkedlist_test.go b/lists/singlylinkedlist/singlylinkedlist_test.go
index c81ba85d..0a45929f 100644
--- a/lists/singlylinkedlist/singlylinkedlist_test.go
+++ b/lists/singlylinkedlist/singlylinkedlist_test.go
@@ -345,14 +345,155 @@ func TestListIteratorFirst(t *testing.T) {
}
}
-func BenchmarkList(b *testing.B) {
+func benchmarkGet(b *testing.B, list *List, size int) {
for i := 0; i < b.N; i++ {
- list := New()
- for n := 0; n < 1000; n++ {
- list.Add(i)
+ for n := 0; n < size; n++ {
+ list.Get(n)
}
- for !list.Empty() {
- list.Remove(0)
+ }
+}
+
+func benchmarkAdd(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, list *List, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ list.Remove(n)
}
}
}
+
+func BenchmarkSinglyLinkedListGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListAdd100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListAdd1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListAdd10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListAdd100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
+
+func BenchmarkSinglyLinkedListRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ list := New()
+ for n := 0; n < size; n++ {
+ list.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, list, size)
+}
diff --git a/maps/hashbidimap/hashbidimap_test.go b/maps/hashbidimap/hashbidimap_test.go
index ca46a069..5527a033 100644
--- a/maps/hashbidimap/hashbidimap_test.go
+++ b/maps/hashbidimap/hashbidimap_test.go
@@ -169,14 +169,155 @@ func sameElements(a []interface{}, b []interface{}) bool {
return true
}
-func BenchmarkMap(b *testing.B) {
+func benchmarkGet(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
- m := New()
- for n := 0; n < 1000; n++ {
+ for n := 0; n < size; n++ {
+ m.Get(n)
+ }
+ }
+}
+
+func benchmarkPut(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Put(n, n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkRemove(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Remove(n)
}
}
}
+
+func BenchmarkHashBidiMapGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashBidiMapGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashBidiMapGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashBidiMapGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashBidiMapPut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashBidiMapPut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashBidiMapPut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashBidiMapPut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashBidiMapRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashBidiMapRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashBidiMapRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashBidiMapRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
diff --git a/maps/hashmap/hashmap_test.go b/maps/hashmap/hashmap_test.go
index c4adf47f..119e9edc 100644
--- a/maps/hashmap/hashmap_test.go
+++ b/maps/hashmap/hashmap_test.go
@@ -137,14 +137,155 @@ func sameElements(a []interface{}, b []interface{}) bool {
return true
}
-func BenchmarkMap(b *testing.B) {
+func benchmarkGet(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
- m := New()
- for n := 0; n < 1000; n++ {
- m.Put(n, n)
+ for n := 0; n < size; n++ {
+ m.Get(n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkPut(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Remove(n)
}
}
}
+
+func BenchmarkHashMapGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashMapGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashMapGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashMapGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkHashMapPut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashMapPut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashMapPut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashMapPut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkHashMapRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashMapRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashMapRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkHashMapRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := New()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go
index 5c41961e..c504e97f 100644
--- a/maps/treebidimap/treebidimap_test.go
+++ b/maps/treebidimap/treebidimap_test.go
@@ -473,14 +473,155 @@ func TestMapIteratorLast(t *testing.T) {
}
}
-func BenchmarkMap(b *testing.B) {
+func benchmarkGet(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
- m := NewWithIntComparators()
- for n := 0; n < 1000; n++ {
+ for n := 0; n < size; n++ {
+ m.Get(n)
+ }
+ }
+}
+
+func benchmarkPut(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Put(n, n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkRemove(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Remove(n)
}
}
}
+
+func BenchmarkTreeBidiMapGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeBidiMapGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeBidiMapGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeBidiMapGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeBidiMapPut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparators()
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeBidiMapPut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeBidiMapPut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeBidiMapPut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeBidiMapRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeBidiMapRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeBidiMapRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeBidiMapRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparators()
+ for n := 0; n < size; n++ {
+ m.Put(n, n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go
index 920b051a..0039601a 100644
--- a/maps/treemap/treemap_test.go
+++ b/maps/treemap/treemap_test.go
@@ -440,14 +440,155 @@ func TestMapIteratorLast(t *testing.T) {
}
}
-func BenchmarkMap(b *testing.B) {
+func benchmarkGet(b *testing.B, m *Map, size int) {
for i := 0; i < b.N; i++ {
- m := NewWithIntComparator()
- for n := 0; n < 1000; n++ {
- m.Put(n, n)
+ for n := 0; n < size; n++ {
+ m.Get(n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkPut(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, m *Map, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
m.Remove(n)
}
}
}
+
+func BenchmarkTreeMapGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeMapGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeMapGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeMapGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, m, size)
+}
+
+func BenchmarkTreeMapPut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparator()
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeMapPut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeMapPut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeMapPut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, m, size)
+}
+
+func BenchmarkTreeMapRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeMapRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeMapRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
+
+func BenchmarkTreeMapRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ m := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ m.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, m, size)
+}
diff --git a/sets/hashset/hashset_test.go b/sets/hashset/hashset_test.go
index b84924b6..b868631d 100644
--- a/sets/hashset/hashset_test.go
+++ b/sets/hashset/hashset_test.go
@@ -62,14 +62,155 @@ func TestSetRemove(t *testing.T) {
}
}
-func BenchmarkSet(b *testing.B) {
+func benchmarkContains(b *testing.B, set *Set, size int) {
for i := 0; i < b.N; i++ {
- set := New()
- for n := 0; n < 1000; n++ {
- set.Add(i)
+ for n := 0; n < size; n++ {
+ set.Contains(n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkAdd(b *testing.B, set *Set, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, set *Set, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
set.Remove(n)
}
}
}
+
+func BenchmarkHashSetContains100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkHashSetContains1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkHashSetContains10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkHashSetContains100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkHashSetAdd100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := New()
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkHashSetAdd1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkHashSetAdd10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkHashSetAdd100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkHashSetRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkHashSetRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkHashSetRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkHashSetRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := New()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
diff --git a/sets/treeset/treeset_test.go b/sets/treeset/treeset_test.go
index 7a5c7e8d..881adc21 100644
--- a/sets/treeset/treeset_test.go
+++ b/sets/treeset/treeset_test.go
@@ -327,14 +327,155 @@ func TestSetIteratorLast(t *testing.T) {
}
}
-func BenchmarkSet(b *testing.B) {
+func benchmarkContains(b *testing.B, set *Set, size int) {
for i := 0; i < b.N; i++ {
- set := NewWithIntComparator()
- for n := 0; n < 1000; n++ {
- set.Add(i)
+ for n := 0; n < size; n++ {
+ set.Contains(n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkAdd(b *testing.B, set *Set, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, set *Set, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
set.Remove(n)
}
}
}
+
+func BenchmarkTreeSetContains100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkTreeSetContains1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkTreeSetContains10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkTreeSetContains100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkContains(b, set, size)
+}
+
+func BenchmarkTreeSetAdd100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := NewWithIntComparator()
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkTreeSetAdd1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkTreeSetAdd10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkTreeSetAdd100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkAdd(b, set, size)
+}
+
+func BenchmarkTreeSetRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkTreeSetRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkTreeSetRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
+
+func BenchmarkTreeSetRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ set := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ set.Add(n)
+ }
+ b.StartTimer()
+ benchmarkRemove(b, set, size)
+}
diff --git a/stacks/arraystack/arraystack_test.go b/stacks/arraystack/arraystack_test.go
index 5b2579fa..48f6be4e 100644
--- a/stacks/arraystack/arraystack_test.go
+++ b/stacks/arraystack/arraystack_test.go
@@ -231,14 +231,103 @@ func TestStackIteratorLast(t *testing.T) {
}
}
-func BenchmarkStack(b *testing.B) {
+func benchmarkPush(b *testing.B, stack *Stack, size int) {
for i := 0; i < b.N; i++ {
- stack := New()
- for n := 0; n < 1000; n++ {
- stack.Push(i)
+ for n := 0; n < size; n++ {
+ stack.Push(n)
}
- for !stack.Empty() {
+ }
+}
+
+func benchmarkPop(b *testing.B, stack *Stack, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
stack.Pop()
}
}
}
+
+func BenchmarkArrayStackPop100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkArrayStackPop1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkArrayStackPop10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkArrayStackPop100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkArrayStackPush100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ stack := New()
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkArrayStackPush1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkArrayStackPush10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkArrayStackPush100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
diff --git a/stacks/linkedliststack/linkedliststack_test.go b/stacks/linkedliststack/linkedliststack_test.go
index ae5031a4..8fb0f437 100644
--- a/stacks/linkedliststack/linkedliststack_test.go
+++ b/stacks/linkedliststack/linkedliststack_test.go
@@ -147,14 +147,103 @@ func TestStackIteratorFirst(t *testing.T) {
}
}
-func BenchmarkStack(b *testing.B) {
+func benchmarkPush(b *testing.B, stack *Stack, size int) {
for i := 0; i < b.N; i++ {
- stack := New()
- for n := 0; n < 1000; n++ {
- stack.Push(i)
+ for n := 0; n < size; n++ {
+ stack.Push(n)
}
- for !stack.Empty() {
+ }
+}
+
+func benchmarkPop(b *testing.B, stack *Stack, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
stack.Pop()
}
}
}
+
+func BenchmarkLinkedListStackPop100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPop1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPop10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPop100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPush100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ stack := New()
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPush1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPush10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
+
+func BenchmarkLinkedListStackPush100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ stack := New()
+ for n := 0; n < size; n++ {
+ stack.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, stack, size)
+}
diff --git a/trees/binaryheap/binaryheap_test.go b/trees/binaryheap/binaryheap_test.go
index 987d806e..36ce9f95 100644
--- a/trees/binaryheap/binaryheap_test.go
+++ b/trees/binaryheap/binaryheap_test.go
@@ -246,15 +246,103 @@ func TestBinaryHeapIteratorLast(t *testing.T) {
}
}
-func BenchmarkBinaryHeap(b *testing.B) {
+func benchmarkPush(b *testing.B, heap *Heap, size int) {
for i := 0; i < b.N; i++ {
- heap := NewWithIntComparator()
- for n := 0; n < 1000; n++ {
- heap.Push(i)
+ for n := 0; n < size; n++ {
+ heap.Push(n)
}
- for !heap.Empty() {
+ }
+}
+
+func benchmarkPop(b *testing.B, heap *Heap, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
heap.Pop()
}
}
+}
+
+func BenchmarkBinaryHeapPop100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPop1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPop10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPop100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPop(b, heap, size)
+}
+func BenchmarkBinaryHeapPush100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ heap := NewWithIntComparator()
+ b.StartTimer()
+ benchmarkPush(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPush1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPush10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, heap, size)
+}
+
+func BenchmarkBinaryHeapPush100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ heap := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ heap.Push(n)
+ }
+ b.StartTimer()
+ benchmarkPush(b, heap, size)
}
diff --git a/trees/btree/btree.go b/trees/btree/btree.go
new file mode 100644
index 00000000..549684f7
--- /dev/null
+++ b/trees/btree/btree.go
@@ -0,0 +1,574 @@
+// Copyright (c) 2015, Emir Pasic. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package btree implements a B tree.
+//
+// According to Knuth's definition, a B-tree of order m is a tree which satisfies the following properties:
+// - Every node has at most m children.
+// - Every non-leaf node (except root) has at least ⌈m/2⌉ children.
+// - The root has at least two children if it is not a leaf node.
+// - A non-leaf node with k children contains k−1 keys.
+// - All leaves appear in the same level
+//
+// Structure is not thread safe.
+//
+// References: https://en.wikipedia.org/wiki/B-tree
+package btree
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/emirpasic/gods/trees"
+ "github.com/emirpasic/gods/utils"
+ "strings"
+)
+
+func assertTreeImplementation() {
+ var _ trees.Tree = (*Tree)(nil)
+}
+
+// Tree holds elements of the B-tree
+type Tree struct {
+ Root *Node // Root node
+ Comparator utils.Comparator // Key comparator
+ size int // Total number of keys in the tree
+ m int // order (maximum number of children)
+}
+
+// Node is a single element within the tree
+type Node struct {
+ Parent *Node
+ Entries []*Entry // Contained keys in node
+ Children []*Node // Children nodes
+}
+
+// Entry represents the key-value pair contained within nodes
+type Entry struct {
+ Key interface{}
+ Value interface{}
+}
+
+// NewWith instantiates a B-tree with the order (maximum number of children) and a custom key comparator.
+func NewWith(order int, comparator utils.Comparator) *Tree {
+ if order < 3 {
+ panic("Invalid order, should be at least 3")
+ }
+ return &Tree{m: order, Comparator: comparator}
+}
+
+// NewWithIntComparator instantiates a B-tree with the order (maximum number of children) and the IntComparator, i.e. keys are of type int.
+func NewWithIntComparator(order int) *Tree {
+ return NewWith(order, utils.IntComparator)
+}
+
+// NewWithStringComparator instantiates a B-tree with the order (maximum number of children) and the StringComparator, i.e. keys are of type string.
+func NewWithStringComparator(order int) *Tree {
+ return NewWith(order, utils.StringComparator)
+}
+
+// Put inserts key-value pair node into the tree.
+// If key already exists, then its value is updated with the new value.
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *Tree) Put(key interface{}, value interface{}) {
+ entry := &Entry{Key: key, Value: value}
+
+ if tree.Root == nil {
+ tree.Root = &Node{Entries: []*Entry{entry}, Children: []*Node{}}
+ tree.size++
+ return
+ }
+
+ if tree.insert(tree.Root, entry) {
+ tree.size++
+ }
+}
+
+// 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 (tree *Tree) Get(key interface{}) (value interface{}, found bool) {
+ node, index, found := tree.searchRecursively(tree.Root, key)
+ if found {
+ return node.Entries[index].Value, true
+ }
+ return nil, false
+}
+
+// Remove remove the node from the tree by key.
+// Key should adhere to the comparator's type assertion, otherwise method panics.
+func (tree *Tree) Remove(key interface{}) {
+ node, index, found := tree.searchRecursively(tree.Root, key)
+ if found {
+ tree.delete(node, index)
+ tree.size--
+ }
+}
+
+// Empty returns true if tree does not contain any nodes
+func (tree *Tree) Empty() bool {
+ return tree.size == 0
+}
+
+// Size returns number of nodes in the tree.
+func (tree *Tree) Size() int {
+ return tree.size
+}
+
+// Keys returns all keys in-order
+func (tree *Tree) Keys() []interface{} {
+ keys := make([]interface{}, tree.size)
+ it := tree.Iterator()
+ for i := 0; it.Next(); i++ {
+ keys[i] = it.Key()
+ }
+ return keys
+}
+
+// Values returns all values in-order based on the key.
+func (tree *Tree) Values() []interface{} {
+ values := make([]interface{}, tree.size)
+ it := tree.Iterator()
+ for i := 0; it.Next(); i++ {
+ values[i] = it.Value()
+ }
+ return values
+}
+
+// Clear removes all nodes from the tree.
+func (tree *Tree) Clear() {
+ tree.Root = nil
+ tree.size = 0
+}
+
+// Height returns the height of the tree.
+func (tree *Tree) Height() int {
+ return tree.Root.height()
+}
+
+// Left returns the left-most (min) node or nil if tree is empty.
+func (tree *Tree) Left() *Node {
+ return tree.left(tree.Root)
+}
+
+// LeftKey returns the left-most (min) key or nil if tree is empty.
+func (tree *Tree) LeftKey() interface{} {
+ if left := tree.Left(); left != nil {
+ return left.Entries[0].Key
+ }
+ return nil
+}
+
+// LeftValue returns the left-most value or nil if tree is empty.
+func (tree *Tree) LeftValue() interface{} {
+ if left := tree.Left(); left != nil {
+ return left.Entries[0].Value
+ }
+ return nil
+}
+
+// Right returns the right-most (max) node or nil if tree is empty.
+func (tree *Tree) Right() *Node {
+ return tree.right(tree.Root)
+}
+
+// RightKey returns the right-most (max) key or nil if tree is empty.
+func (tree *Tree) RightKey() interface{} {
+ if right := tree.Right(); right != nil {
+ return right.Entries[len(right.Entries)-1].Key
+ }
+ return nil
+}
+
+// RightValue returns the right-most value or nil if tree is empty.
+func (tree *Tree) RightValue() interface{} {
+ if right := tree.Right(); right != nil {
+ return right.Entries[len(right.Entries)-1].Value
+ }
+ return nil
+}
+
+// String returns a string representation of container (for debugging purposes)
+func (tree *Tree) String() string {
+ var buffer bytes.Buffer
+ buffer.WriteString("BTree\n")
+ if !tree.Empty() {
+ tree.output(&buffer, tree.Root, 0, true)
+ }
+ return buffer.String()
+}
+
+func (entry *Entry) String() string {
+ return fmt.Sprintf("%v", entry.Key)
+}
+
+func (tree *Tree) output(buffer *bytes.Buffer, node *Node, level int, isTail bool) {
+ for e := 0; e < len(node.Entries)+1; e++ {
+ if e < len(node.Children) {
+ tree.output(buffer, node.Children[e], level+1, true)
+ }
+ if e < len(node.Entries) {
+ buffer.WriteString(strings.Repeat(" ", level))
+ buffer.WriteString(fmt.Sprintf("%v", node.Entries[e].Key) + "\n")
+ }
+ }
+}
+
+func (node *Node) height() int {
+ height := 0
+ for ; node != nil; node = node.Children[0] {
+ height++
+ if len(node.Children) == 0 {
+ break
+ }
+ }
+ return height
+}
+
+func (tree *Tree) isLeaf(node *Node) bool {
+ return len(node.Children) == 0
+}
+
+func (tree *Tree) isFull(node *Node) bool {
+ return len(node.Entries) == tree.maxEntries()
+}
+
+func (tree *Tree) shouldSplit(node *Node) bool {
+ return len(node.Entries) > tree.maxEntries()
+}
+
+func (tree *Tree) maxChildren() int {
+ return tree.m
+}
+
+func (tree *Tree) minChildren() int {
+ return (tree.m + 1) / 2 // ceil(m/2)
+}
+
+func (tree *Tree) maxEntries() int {
+ return tree.maxChildren() - 1
+}
+
+func (tree *Tree) minEntries() int {
+ return tree.minChildren() - 1
+}
+
+func (tree *Tree) middle() int {
+ return (tree.m - 1) / 2 // "-1" to favor right nodes to have more keys when splitting
+}
+
+// search searches only within the single node among its entries
+func (tree *Tree) search(node *Node, key interface{}) (index int, found bool) {
+ low, high := 0, len(node.Entries)-1
+ var mid int
+ for low <= high {
+ mid = (high + low) / 2
+ compare := tree.Comparator(key, node.Entries[mid].Key)
+ switch {
+ case compare > 0:
+ low = mid + 1
+ case compare < 0:
+ high = mid - 1
+ case compare == 0:
+ return mid, true
+ }
+ }
+ return low, false
+}
+
+// searchRecursively searches recursively down the tree starting at the startNode
+func (tree *Tree) searchRecursively(startNode *Node, key interface{}) (node *Node, index int, found bool) {
+ if tree.Empty() {
+ return nil, -1, false
+ }
+ node = startNode
+ for {
+ index, found = tree.search(node, key)
+ if found {
+ return node, index, true
+ }
+ if tree.isLeaf(node) {
+ return nil, -1, false
+ }
+ node = node.Children[index]
+ }
+}
+
+func (tree *Tree) insert(node *Node, entry *Entry) (inserted bool) {
+ if tree.isLeaf(node) {
+ return tree.insertIntoLeaf(node, entry)
+ }
+ return tree.insertIntoInternal(node, entry)
+}
+
+func (tree *Tree) insertIntoLeaf(node *Node, entry *Entry) (inserted bool) {
+ insertPosition, found := tree.search(node, entry.Key)
+ if found {
+ node.Entries[insertPosition] = entry
+ return false
+ }
+ // Insert entry's key in the middle of the node
+ node.Entries = append(node.Entries, nil)
+ copy(node.Entries[insertPosition+1:], node.Entries[insertPosition:])
+ node.Entries[insertPosition] = entry
+ tree.split(node)
+ return true
+}
+
+func (tree *Tree) insertIntoInternal(node *Node, entry *Entry) (inserted bool) {
+ insertPosition, found := tree.search(node, entry.Key)
+ if found {
+ node.Entries[insertPosition] = entry
+ return false
+ }
+ return tree.insert(node.Children[insertPosition], entry)
+}
+
+func (tree *Tree) split(node *Node) {
+ if !tree.shouldSplit(node) {
+ return
+ }
+
+ if node == tree.Root {
+ tree.splitRoot()
+ return
+ }
+
+ tree.splitNonRoot(node)
+}
+
+func (tree *Tree) splitNonRoot(node *Node) {
+ middle := tree.middle()
+ parent := node.Parent
+
+ left := &Node{Entries: append([]*Entry(nil), node.Entries[:middle]...), Parent: parent}
+ right := &Node{Entries: append([]*Entry(nil), node.Entries[middle+1:]...), Parent: parent}
+
+ // Move children from the node to be split into left and right nodes
+ if !tree.isLeaf(node) {
+ left.Children = append([]*Node(nil), node.Children[:middle+1]...)
+ right.Children = append([]*Node(nil), node.Children[middle+1:]...)
+ setParent(left.Children, left)
+ setParent(right.Children, right)
+ }
+
+ insertPosition, _ := tree.search(parent, node.Entries[middle].Key)
+
+ // Insert middle key into parent
+ parent.Entries = append(parent.Entries, nil)
+ copy(parent.Entries[insertPosition+1:], parent.Entries[insertPosition:])
+ parent.Entries[insertPosition] = node.Entries[middle]
+
+ // Set child left of inserted key in parent to the created left node
+ parent.Children[insertPosition] = left
+
+ // Set child right of inserted key in parent to the created right node
+ parent.Children = append(parent.Children, nil)
+ copy(parent.Children[insertPosition+2:], parent.Children[insertPosition+1:])
+ parent.Children[insertPosition+1] = right
+
+ tree.split(parent)
+}
+
+func (tree *Tree) splitRoot() {
+ middle := tree.middle()
+
+ left := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[:middle]...)}
+ right := &Node{Entries: append([]*Entry(nil), tree.Root.Entries[middle+1:]...)}
+
+ // Move children from the node to be split into left and right nodes
+ if !tree.isLeaf(tree.Root) {
+ left.Children = append([]*Node(nil), tree.Root.Children[:middle+1]...)
+ right.Children = append([]*Node(nil), tree.Root.Children[middle+1:]...)
+ setParent(left.Children, left)
+ setParent(right.Children, right)
+ }
+
+ // Root is a node with one entry and two children (left and right)
+ newRoot := &Node{
+ Entries: []*Entry{tree.Root.Entries[middle]},
+ Children: []*Node{left, right},
+ }
+
+ left.Parent = newRoot
+ right.Parent = newRoot
+ tree.Root = newRoot
+}
+
+func setParent(nodes []*Node, parent *Node) {
+ for _, node := range nodes {
+ node.Parent = parent
+ }
+}
+
+func (tree *Tree) left(node *Node) *Node {
+ if tree.Empty() {
+ return nil
+ }
+ current := node
+ for {
+ if tree.isLeaf(current) {
+ return current
+ }
+ current = current.Children[0]
+ }
+}
+
+func (tree *Tree) right(node *Node) *Node {
+ if tree.Empty() {
+ return nil
+ }
+ current := node
+ for {
+ if tree.isLeaf(current) {
+ return current
+ }
+ current = current.Children[len(current.Children)-1]
+ }
+}
+
+// leftSibling returns the node's left sibling and child index (in parent) if it exists, otherwise (nil,-1)
+// key is any of keys in node (could even be deleted).
+func (tree *Tree) leftSibling(node *Node, key interface{}) (*Node, int) {
+ if node.Parent != nil {
+ index, _ := tree.search(node.Parent, key)
+ index--
+ if index >= 0 && index < len(node.Parent.Children) {
+ return node.Parent.Children[index], index
+ }
+ }
+ return nil, -1
+}
+
+// rightSibling returns the node's right sibling and child index (in parent) if it exists, otherwise (nil,-1)
+// key is any of keys in node (could even be deleted).
+func (tree *Tree) rightSibling(node *Node, key interface{}) (*Node, int) {
+ if node.Parent != nil {
+ index, _ := tree.search(node.Parent, key)
+ index++
+ if index < len(node.Parent.Children) {
+ return node.Parent.Children[index], index
+ }
+ }
+ return nil, -1
+}
+
+// delete deletes an entry in node at entries' index
+// ref.: https://en.wikipedia.org/wiki/B-tree#Deletion
+func (tree *Tree) delete(node *Node, index int) {
+ // deleting from a leaf node
+ if tree.isLeaf(node) {
+ deletedKey := node.Entries[index].Key
+ tree.deleteEntry(node, index)
+ tree.rebalance(node, deletedKey)
+ if len(tree.Root.Entries) == 0 {
+ tree.Root = nil
+ }
+ return
+ }
+
+ // deleting from an internal node
+ leftLargestNode := tree.right(node.Children[index]) // largest node in the left sub-tree (assumed to exist)
+ leftLargestEntryIndex := len(leftLargestNode.Entries) - 1
+ node.Entries[index] = leftLargestNode.Entries[leftLargestEntryIndex]
+ deletedKey := leftLargestNode.Entries[leftLargestEntryIndex].Key
+ tree.deleteEntry(leftLargestNode, leftLargestEntryIndex)
+ tree.rebalance(leftLargestNode, deletedKey)
+}
+
+// rebalance rebalances the tree after deletion if necessary and returns true, otherwise false.
+// Note that we first delete the entry and then call rebalance, thus the passed deleted key as reference.
+func (tree *Tree) rebalance(node *Node, deletedKey interface{}) {
+ // check if rebalancing is needed
+ if node == nil || len(node.Entries) >= tree.minEntries() {
+ return
+ }
+
+ // try to borrow from left sibling
+ leftSibling, leftSiblingIndex := tree.leftSibling(node, deletedKey)
+ if leftSibling != nil && len(leftSibling.Entries) > tree.minEntries() {
+ // rotate right
+ node.Entries = append([]*Entry{node.Parent.Entries[leftSiblingIndex]}, node.Entries...) // prepend parent's separator entry to node's entries
+ node.Parent.Entries[leftSiblingIndex] = leftSibling.Entries[len(leftSibling.Entries)-1]
+ tree.deleteEntry(leftSibling, len(leftSibling.Entries)-1)
+ if !tree.isLeaf(leftSibling) {
+ leftSiblingRightMostChild := leftSibling.Children[len(leftSibling.Children)-1]
+ leftSiblingRightMostChild.Parent = node
+ node.Children = append([]*Node{leftSiblingRightMostChild}, node.Children...)
+ tree.deleteChild(leftSibling, len(leftSibling.Children)-1)
+ }
+ return
+ }
+
+ // try to borrow from right sibling
+ rightSibling, rightSiblingIndex := tree.rightSibling(node, deletedKey)
+ if rightSibling != nil && len(rightSibling.Entries) > tree.minEntries() {
+ // rotate left
+ node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1]) // append parent's separator entry to node's entries
+ node.Parent.Entries[rightSiblingIndex-1] = rightSibling.Entries[0]
+ tree.deleteEntry(rightSibling, 0)
+ if !tree.isLeaf(rightSibling) {
+ rightSiblingLeftMostChild := rightSibling.Children[0]
+ rightSiblingLeftMostChild.Parent = node
+ node.Children = append(node.Children, rightSiblingLeftMostChild)
+ tree.deleteChild(rightSibling, 0)
+ }
+ return
+ }
+
+ // merge with siblings
+ if rightSibling != nil {
+ // merge with right sibling
+ node.Entries = append(node.Entries, node.Parent.Entries[rightSiblingIndex-1])
+ node.Entries = append(node.Entries, rightSibling.Entries...)
+ deletedKey = node.Parent.Entries[rightSiblingIndex-1].Key
+ tree.deleteEntry(node.Parent, rightSiblingIndex-1)
+ tree.appendChildren(node.Parent.Children[rightSiblingIndex], node)
+ tree.deleteChild(node.Parent, rightSiblingIndex)
+ } else if leftSibling != nil {
+ // merge with left sibling
+ entries := append([]*Entry(nil), leftSibling.Entries...)
+ entries = append(entries, node.Parent.Entries[leftSiblingIndex])
+ node.Entries = append(entries, node.Entries...)
+ deletedKey = node.Parent.Entries[leftSiblingIndex].Key
+ tree.deleteEntry(node.Parent, leftSiblingIndex)
+ tree.prependChildren(node.Parent.Children[leftSiblingIndex], node)
+ tree.deleteChild(node.Parent, leftSiblingIndex)
+ }
+
+ // make the merged node the root if its parent was the root and the root is empty
+ if node.Parent == tree.Root && len(tree.Root.Entries) == 0 {
+ tree.Root = node
+ node.Parent = nil
+ return
+ }
+
+ // parent might underflow, so try to rebalance if necessary
+ tree.rebalance(node.Parent, deletedKey)
+}
+
+func (tree *Tree) prependChildren(fromNode *Node, toNode *Node) {
+ children := append([]*Node(nil), fromNode.Children...)
+ toNode.Children = append(children, toNode.Children...)
+ setParent(fromNode.Children, toNode)
+}
+
+func (tree *Tree) appendChildren(fromNode *Node, toNode *Node) {
+ toNode.Children = append(toNode.Children, fromNode.Children...)
+ setParent(fromNode.Children, toNode)
+}
+
+func (tree *Tree) deleteEntry(node *Node, index int) {
+ copy(node.Entries[index:], node.Entries[index+1:])
+ node.Entries[len(node.Entries)-1] = nil
+ node.Entries = node.Entries[:len(node.Entries)-1]
+}
+
+func (tree *Tree) deleteChild(node *Node, index int) {
+ if index >= len(node.Children) {
+ return
+ }
+ copy(node.Children[index:], node.Children[index+1:])
+ node.Children[len(node.Children)-1] = nil
+ node.Children = node.Children[:len(node.Children)-1]
+}
diff --git a/trees/btree/btree_test.go b/trees/btree/btree_test.go
new file mode 100644
index 00000000..4705bc10
--- /dev/null
+++ b/trees/btree/btree_test.go
@@ -0,0 +1,1228 @@
+// Copyright (c) 2015, Emir Pasic. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package btree
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestBTreeGet1(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ tree.Put(3, "c")
+ tree.Put(4, "d")
+ tree.Put(5, "e")
+ tree.Put(6, "f")
+ tree.Put(7, "g")
+
+ tests := [][]interface{}{
+ {0, nil, false},
+ {1, "a", true},
+ {2, "b", true},
+ {3, "c", true},
+ {4, "d", true},
+ {5, "e", true},
+ {6, "f", true},
+ {7, "g", true},
+ {8, nil, false},
+ }
+
+ for _, test := range tests {
+ if value, found := tree.Get(test[0]); value != test[1] || found != test[2] {
+ t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2])
+ }
+ }
+}
+
+func TestBTreeGet2(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(7, "g")
+ tree.Put(9, "i")
+ tree.Put(10, "j")
+ tree.Put(6, "f")
+ tree.Put(3, "c")
+ tree.Put(4, "d")
+ tree.Put(5, "e")
+ tree.Put(8, "h")
+ tree.Put(2, "b")
+ tree.Put(1, "a")
+
+ tests := [][]interface{}{
+ {0, nil, false},
+ {1, "a", true},
+ {2, "b", true},
+ {3, "c", true},
+ {4, "d", true},
+ {5, "e", true},
+ {6, "f", true},
+ {7, "g", true},
+ {8, "h", true},
+ {9, "i", true},
+ {10, "j", true},
+ {11, nil, false},
+ }
+
+ for _, test := range tests {
+ if value, found := tree.Get(test[0]); value != test[1] || found != test[2] {
+ t.Errorf("Got %v,%v expected %v,%v", value, found, test[1], test[2])
+ }
+ }
+}
+
+func TestBTreePut1(t *testing.T) {
+ // https://upload.wikimedia.org/wikipedia/commons/3/33/B_tree_insertion_example.png
+ tree := NewWithIntComparator(3)
+ assertValidTree(t, tree, 0)
+
+ tree.Put(1, 0)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{1}, false)
+
+ tree.Put(2, 1)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}, false)
+
+ tree.Put(3, 2)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true)
+
+ tree.Put(4, 2)
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}, true)
+
+ tree.Put(5, 2)
+ assertValidTree(t, tree, 5)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{5}, true)
+
+ tree.Put(6, 2)
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}, true)
+
+ tree.Put(7, 2)
+ assertValidTree(t, tree, 7)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true)
+}
+
+func TestBTreePut2(t *testing.T) {
+ tree := NewWithIntComparator(4)
+ assertValidTree(t, tree, 0)
+
+ tree.Put(0, 0)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{0}, false)
+
+ tree.Put(2, 2)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{0, 2}, false)
+
+ tree.Put(1, 1)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}, false)
+
+ tree.Put(1, 1)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 3, 0, []int{0, 1, 2}, false)
+
+ tree.Put(3, 3)
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{2, 3}, true)
+
+ tree.Put(4, 4)
+ assertValidTree(t, tree, 5)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{2, 3, 4}, true)
+
+ tree.Put(5, 5)
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{1, 3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{4, 5}, true)
+}
+
+func TestBTreePut3(t *testing.T) {
+ // http://www.geeksforgeeks.org/b-tree-set-1-insert-2/
+ tree := NewWithIntComparator(6)
+ assertValidTree(t, tree, 0)
+
+ tree.Put(10, 0)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{10}, false)
+
+ tree.Put(20, 1)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{10, 20}, false)
+
+ tree.Put(30, 2)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 3, 0, []int{10, 20, 30}, false)
+
+ tree.Put(40, 3)
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 4, 0, []int{10, 20, 30, 40}, false)
+
+ tree.Put(50, 4)
+ assertValidTree(t, tree, 5)
+ assertValidTreeNode(t, tree.Root, 5, 0, []int{10, 20, 30, 40, 50}, false)
+
+ tree.Put(60, 5)
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 3, 0, []int{40, 50, 60}, true)
+
+ tree.Put(70, 6)
+ assertValidTree(t, tree, 7)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 4, 0, []int{40, 50, 60, 70}, true)
+
+ tree.Put(80, 7)
+ assertValidTree(t, tree, 8)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{30}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 5, 0, []int{40, 50, 60, 70, 80}, true)
+
+ tree.Put(90, 8)
+ assertValidTree(t, tree, 9)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{30, 60}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{10, 20}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{40, 50}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 3, 0, []int{70, 80, 90}, true)
+}
+
+func TestBTreePut4(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ assertValidTree(t, tree, 0)
+
+ tree.Put(6, nil)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{6}, false)
+
+ tree.Put(5, nil)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{5, 6}, false)
+
+ tree.Put(4, nil)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{5}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(3, nil)
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{5}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{3, 4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(2, nil)
+ assertValidTree(t, tree, 5)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true)
+
+ tree.Put(1, nil)
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{3, 5}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{1, 2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{6}, true)
+
+ tree.Put(0, nil)
+ assertValidTree(t, tree, 7)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(-1, nil)
+ assertValidTree(t, tree, 8)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{-1, 0}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(-2, nil)
+ assertValidTree(t, tree, 9)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 3, []int{-1, 1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{-2}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[2], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(-3, nil)
+ assertValidTree(t, tree, 10)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 3, []int{-1, 1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{-3, -2}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[2], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{6}, true)
+
+ tree.Put(-4, nil)
+ assertValidTree(t, tree, 11)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{-1, 3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{-3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 2, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{-4}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{-2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[2].Children[0], 1, 0, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[2].Children[1], 1, 0, []int{6}, true)
+}
+
+func TestBTreeRemove1(t *testing.T) {
+ // empty
+ tree := NewWithIntComparator(3)
+ tree.Remove(1)
+ assertValidTree(t, tree, 0)
+}
+
+func TestBTreeRemove2(t *testing.T) {
+ // leaf node (no underflow)
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+
+ tree.Remove(1)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{2}, false)
+
+ tree.Remove(2)
+ assertValidTree(t, tree, 0)
+}
+
+func TestBTreeRemove3(t *testing.T) {
+ // merge with right (underflow)
+ {
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+
+ tree.Remove(1)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{2, 3}, false)
+ }
+ // merge with left (underflow)
+ {
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+
+ tree.Remove(3)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{1, 2}, false)
+ }
+}
+
+func TestBTreeRemove4(t *testing.T) {
+ // rotate left (underflow)
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+ tree.Put(4, nil)
+
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 2, 0, []int{3, 4}, true)
+
+ tree.Remove(1)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{3}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{4}, true)
+}
+
+func TestBTreeRemove5(t *testing.T) {
+ // rotate right (underflow)
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+ tree.Put(0, nil)
+
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{2}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{0, 1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true)
+
+ tree.Remove(3)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{1}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{0}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{2}, true)
+}
+
+func TestBTreeRemove6(t *testing.T) {
+ // root height reduction after a series of underflows on right side
+ // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+ tree.Put(4, nil)
+ tree.Put(5, nil)
+ tree.Put(6, nil)
+ tree.Put(7, nil)
+
+ assertValidTree(t, tree, 7)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true)
+
+ tree.Remove(7)
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{2, 4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 2, 0, []int{5, 6}, true)
+}
+
+func TestBTreeRemove7(t *testing.T) {
+ // root height reduction after a series of underflows on left side
+ // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+ tree.Put(4, nil)
+ tree.Put(5, nil)
+ tree.Put(6, nil)
+ tree.Put(7, nil)
+
+ assertValidTree(t, tree, 7)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{6}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true)
+
+ tree.Remove(1) // series of underflows
+ assertValidTree(t, tree, 6)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{4, 6}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{2, 3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{7}, true)
+
+ // clear all remaining
+ tree.Remove(2)
+ assertValidTree(t, tree, 5)
+ assertValidTreeNode(t, tree.Root, 2, 3, []int{4, 6}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[2], 1, 0, []int{7}, true)
+
+ tree.Remove(3)
+ assertValidTree(t, tree, 4)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 2, 0, []int{4, 5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{7}, true)
+
+ tree.Remove(4)
+ assertValidTree(t, tree, 3)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 0, []int{7}, true)
+
+ tree.Remove(5)
+ assertValidTree(t, tree, 2)
+ assertValidTreeNode(t, tree.Root, 2, 0, []int{6, 7}, false)
+
+ tree.Remove(6)
+ assertValidTree(t, tree, 1)
+ assertValidTreeNode(t, tree.Root, 1, 0, []int{7}, false)
+
+ tree.Remove(7)
+ assertValidTree(t, tree, 0)
+}
+
+func TestBTreeRemove8(t *testing.T) {
+ // use simulator: https://www.cs.usfca.edu/~galles/visualization/BTree.html
+ tree := NewWithIntComparator(3)
+ tree.Put(1, nil)
+ tree.Put(2, nil)
+ tree.Put(3, nil)
+ tree.Put(4, nil)
+ tree.Put(5, nil)
+ tree.Put(6, nil)
+ tree.Put(7, nil)
+ tree.Put(8, nil)
+ tree.Put(9, nil)
+
+ assertValidTree(t, tree, 9)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{4}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{2}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 2, 3, []int{6, 8}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 1, 0, []int{1}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{3}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{7}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[2], 1, 0, []int{9}, true)
+
+ tree.Remove(1)
+ assertValidTree(t, tree, 8)
+ assertValidTreeNode(t, tree.Root, 1, 2, []int{6}, false)
+ assertValidTreeNode(t, tree.Root.Children[0], 1, 2, []int{4}, true)
+ assertValidTreeNode(t, tree.Root.Children[1], 1, 2, []int{8}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[0], 2, 0, []int{2, 3}, true)
+ assertValidTreeNode(t, tree.Root.Children[0].Children[1], 1, 0, []int{5}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[0], 1, 0, []int{7}, true)
+ assertValidTreeNode(t, tree.Root.Children[1].Children[1], 1, 0, []int{9}, true)
+}
+
+func TestBTreeRemove9(t *testing.T) {
+ const max = 1000
+ orders := []int{3, 4, 5, 6, 7, 8, 9, 10, 20, 100, 500, 1000, 5000, 10000}
+ for _, order := range orders {
+
+ tree := NewWithIntComparator(order)
+
+ {
+ for i := 1; i <= max; i++ {
+ tree.Put(i, i)
+ }
+ assertValidTree(t, tree, max)
+
+ for i := 1; i <= max; i++ {
+ if _, found := tree.Get(i); !found {
+ t.Errorf("Not found %v", i)
+ }
+ }
+
+ for i := 1; i <= max; i++ {
+ tree.Remove(i)
+ }
+ assertValidTree(t, tree, 0)
+ }
+
+ {
+ for i := max; i > 0; i-- {
+ tree.Put(i, i)
+ }
+ assertValidTree(t, tree, max)
+
+ for i := max; i > 0; i-- {
+ if _, found := tree.Get(i); !found {
+ t.Errorf("Not found %v", i)
+ }
+ }
+
+ for i := max; i > 0; i-- {
+ tree.Remove(i)
+ }
+ assertValidTree(t, tree, 0)
+ }
+ }
+}
+
+func TestBTreeHeight(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(1, 0)
+ if actualValue, expectedValue := tree.Height(), 1; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(2, 1)
+ if actualValue, expectedValue := tree.Height(), 1; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(3, 2)
+ if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(4, 2)
+ if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(5, 2)
+ if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(6, 2)
+ if actualValue, expectedValue := tree.Height(), 2; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Put(7, 2)
+ if actualValue, expectedValue := tree.Height(), 3; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ tree.Remove(1)
+ tree.Remove(2)
+ tree.Remove(3)
+ tree.Remove(4)
+ tree.Remove(5)
+ tree.Remove(6)
+ tree.Remove(7)
+ if actualValue, expectedValue := tree.Height(), 0; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeLeftAndRight(t *testing.T) {
+ tree := NewWithIntComparator(3)
+
+ if actualValue := tree.Left(); actualValue != nil {
+ t.Errorf("Got %v expected %v", actualValue, nil)
+ }
+ if actualValue := tree.Right(); actualValue != nil {
+ t.Errorf("Got %v expected %v", actualValue, nil)
+ }
+
+ tree.Put(1, "a")
+ tree.Put(5, "e")
+ tree.Put(6, "f")
+ tree.Put(7, "g")
+ tree.Put(3, "c")
+ tree.Put(4, "d")
+ tree.Put(1, "x") // overwrite
+ tree.Put(2, "b")
+
+ if actualValue, expectedValue := tree.LeftKey(), 1; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := tree.LeftValue(), "x"; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+
+ if actualValue, expectedValue := tree.RightKey(), 7; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := tree.RightValue(), "g"; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIteratorValuesAndKeys(t *testing.T) {
+ tree := NewWithIntComparator(4)
+ tree.Put(4, "d")
+ tree.Put(5, "e")
+ tree.Put(6, "f")
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(7, "g")
+ tree.Put(2, "b")
+ tree.Put(1, "x") // override
+ if actualValue, expectedValue := fmt.Sprintf("%d%d%d%d%d%d%d", tree.Keys()...), "1234567"; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := fmt.Sprintf("%s%s%s%s%s%s%s", tree.Values()...), "xbcdefg"; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue := tree.Size(); actualValue != 7 {
+ t.Errorf("Got %v expected %v", actualValue, 7)
+ }
+}
+
+func TestBTreeIteratorNextOnEmpty(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ it := tree.Iterator()
+ for it.Next() {
+ t.Errorf("Shouldn't iterate on empty tree")
+ }
+}
+
+func TestBTreeIteratorPrevOnEmpty(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ it := tree.Iterator()
+ for it.Prev() {
+ t.Errorf("Shouldn't iterate on empty tree")
+ }
+}
+
+func TestBTreeIterator1Next(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(5, "e")
+ tree.Put(6, "f")
+ tree.Put(7, "g")
+ tree.Put(3, "c")
+ tree.Put(4, "d")
+ tree.Put(1, "x")
+ tree.Put(2, "b")
+ tree.Put(1, "a") //overwrite
+ it := tree.Iterator()
+ count := 0
+ for it.Next() {
+ count++
+ key := it.Key()
+ switch key {
+ case count:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+ if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator1Prev(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(5, "e")
+ tree.Put(6, "f")
+ tree.Put(7, "g")
+ tree.Put(3, "c")
+ tree.Put(4, "d")
+ tree.Put(1, "x")
+ tree.Put(2, "b")
+ tree.Put(1, "a") //overwrite
+ it := tree.Iterator()
+ for it.Next() {
+ }
+ countDown := tree.size
+ for it.Prev() {
+ key := it.Key()
+ switch key {
+ case countDown:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ countDown--
+ }
+ if actualValue, expectedValue := countDown, 0; actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator2Next(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it := tree.Iterator()
+ count := 0
+ for it.Next() {
+ count++
+ key := it.Key()
+ switch key {
+ case count:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+ if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator2Prev(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it := tree.Iterator()
+ for it.Next() {
+ }
+ countDown := tree.size
+ for it.Prev() {
+ key := it.Key()
+ switch key {
+ case countDown:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ countDown--
+ }
+ if actualValue, expectedValue := countDown, 0; actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator3Next(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(1, "a")
+ it := tree.Iterator()
+ count := 0
+ for it.Next() {
+ count++
+ key := it.Key()
+ switch key {
+ case count:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+ if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator3Prev(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(1, "a")
+ it := tree.Iterator()
+ for it.Next() {
+ }
+ countDown := tree.size
+ for it.Prev() {
+ key := it.Key()
+ switch key {
+ case countDown:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := key, countDown; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ countDown--
+ }
+ if actualValue, expectedValue := countDown, 0; actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator4Next(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(13, 5)
+ tree.Put(8, 3)
+ tree.Put(17, 7)
+ tree.Put(1, 1)
+ tree.Put(11, 4)
+ tree.Put(15, 6)
+ tree.Put(25, 9)
+ tree.Put(6, 2)
+ tree.Put(22, 8)
+ tree.Put(27, 10)
+ it := tree.Iterator()
+ count := 0
+ for it.Next() {
+ count++
+ value := it.Value()
+ switch value {
+ case count:
+ if actualValue, expectedValue := value, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := value, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+ if actualValue, expectedValue := count, tree.Size(); actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIterator4Prev(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(13, 5)
+ tree.Put(8, 3)
+ tree.Put(17, 7)
+ tree.Put(1, 1)
+ tree.Put(11, 4)
+ tree.Put(15, 6)
+ tree.Put(25, 9)
+ tree.Put(6, 2)
+ tree.Put(22, 8)
+ tree.Put(27, 10)
+ it := tree.Iterator()
+ count := tree.Size()
+ for it.Next() {
+ }
+ for it.Prev() {
+ value := it.Value()
+ switch value {
+ case count:
+ if actualValue, expectedValue := value, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ default:
+ if actualValue, expectedValue := value, count; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ count--
+ }
+ if actualValue, expectedValue := count, 0; actualValue != expectedValue {
+ t.Errorf("Size different. Got %v expected %v", actualValue, expectedValue)
+ }
+}
+
+func TestBTreeIteratorBegin(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it := tree.Iterator()
+
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ it.Begin()
+
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ for it.Next() {
+ }
+
+ it.Begin()
+
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ it.Next()
+ if key, value := it.Key(), it.Value(); key != 1 || value != "a" {
+ t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a")
+ }
+}
+
+func TestBTreeIteratorEnd(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ it := tree.Iterator()
+
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ it.End()
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it.End()
+ if it.node != nil {
+ t.Errorf("Got %v expected %v", it.node, nil)
+ }
+
+ it.Prev()
+ if key, value := it.Key(), it.Value(); key != 3 || value != "c" {
+ t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c")
+ }
+}
+
+func TestBTreeIteratorFirst(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it := tree.Iterator()
+ if actualValue, expectedValue := it.First(), true; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if key, value := it.Key(), it.Value(); key != 1 || value != "a" {
+ t.Errorf("Got %v,%v expected %v,%v", key, value, 1, "a")
+ }
+}
+
+func TestBTreeIteratorLast(t *testing.T) {
+ tree := NewWithIntComparator(3)
+ tree.Put(3, "c")
+ tree.Put(1, "a")
+ tree.Put(2, "b")
+ it := tree.Iterator()
+ if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if key, value := it.Key(), it.Value(); key != 3 || value != "c" {
+ t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c")
+ }
+}
+
+func TestBTree_search(t *testing.T) {
+ {
+ tree := NewWithIntComparator(3)
+ tree.Root = &Node{Entries: []*Entry{}, Children: make([]*Node, 0)}
+ tests := [][]interface{}{
+ {0, 0, false},
+ }
+ for _, test := range tests {
+ index, found := tree.search(tree.Root, test[0])
+ if actualValue, expectedValue := index, test[1]; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := found, test[2]; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+ {
+ tree := NewWithIntComparator(3)
+ tree.Root = &Node{Entries: []*Entry{{2, 0}, {4, 1}, {6, 2}}, Children: []*Node{}}
+ tests := [][]interface{}{
+ {0, 0, false},
+ {1, 0, false},
+ {2, 0, true},
+ {3, 1, false},
+ {4, 1, true},
+ {5, 2, false},
+ {6, 2, true},
+ {7, 3, false},
+ }
+ for _, test := range tests {
+ index, found := tree.search(tree.Root, test[0])
+ if actualValue, expectedValue := index, test[1]; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := found, test[2]; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v", actualValue, expectedValue)
+ }
+ }
+ }
+}
+
+func assertValidTree(t *testing.T, tree *Tree, expectedSize int) {
+ if actualValue, expectedValue := tree.size, expectedSize; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v for tree size", actualValue, expectedValue)
+ }
+}
+
+func assertValidTreeNode(t *testing.T, node *Node, expectedEntries int, expectedChildren int, keys []int, hasParent bool) {
+ if actualValue, expectedValue := node.Parent != nil, hasParent; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v for hasParent", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := len(node.Entries), expectedEntries; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v for entries size", actualValue, expectedValue)
+ }
+ if actualValue, expectedValue := len(node.Children), expectedChildren; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v for children size", actualValue, expectedValue)
+ }
+ for i, key := range keys {
+ if actualValue, expectedValue := node.Entries[i].Key, key; actualValue != expectedValue {
+ t.Errorf("Got %v expected %v for key", actualValue, expectedValue)
+ }
+ }
+}
+
+func benchmarkGet(b *testing.B, tree *Tree, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ tree.Get(n)
+ }
+ }
+}
+
+func benchmarkPut(b *testing.B, tree *Tree, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, tree *Tree, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ tree.Remove(n)
+ }
+ }
+}
+
+func BenchmarkBTreeGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkBTreeGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkBTreeGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkBTreeGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkBTreePut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator(128)
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkBTreePut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkBTreePut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkBTreePut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkBTreeRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkBTreeRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkBTreeRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkBTreeRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator(128)
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
diff --git a/trees/btree/iterator.go b/trees/btree/iterator.go
new file mode 100644
index 00000000..840db687
--- /dev/null
+++ b/trees/btree/iterator.go
@@ -0,0 +1,193 @@
+// Copyright (c) 2015, Emir Pasic. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package btree
+
+import "github.com/emirpasic/gods/containers"
+
+func assertIteratorImplementation() {
+ var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
+}
+
+// Iterator holding the iterator's state
+type Iterator struct {
+ tree *Tree
+ node *Node
+ entry *Entry
+ position position
+}
+
+type position byte
+
+const (
+ begin, between, end position = 0, 1, 2
+)
+
+// Iterator returns a stateful iterator whose elements are key/value pairs.
+func (tree *Tree) Iterator() Iterator {
+ return Iterator{tree: tree, node: nil, position: begin}
+}
+
+// Next moves the iterator to the next element and returns true if there was a next element in the container.
+// If Next() returns true, then next element's key and value can be retrieved by Key() and Value().
+// If Next() was called for the first time, then it will point the iterator to the first element if it exists.
+// Modifies the state of the iterator.
+func (iterator *Iterator) Next() bool {
+ // If already at end, go to end
+ if iterator.position == end {
+ goto end
+ }
+ // If at beginning, get the left-most entry in the tree
+ if iterator.position == begin {
+ left := iterator.tree.Left()
+ if left == nil {
+ goto end
+ }
+ iterator.node = left
+ iterator.entry = left.Entries[0]
+ goto between
+ }
+ {
+ // Find current entry position in current node
+ e, _ := iterator.tree.search(iterator.node, iterator.entry.Key)
+ // Try to go down to the child right of the current entry
+ if e+1 < len(iterator.node.Children) {
+ iterator.node = iterator.node.Children[e+1]
+ // Try to go down to the child left of the current node
+ for len(iterator.node.Children) > 0 {
+ iterator.node = iterator.node.Children[0]
+ }
+ // Return the left-most entry
+ iterator.entry = iterator.node.Entries[0]
+ goto between
+ }
+ // Above assures that we have reached a leaf node, so return the next entry in current node (if any)
+ if e+1 < len(iterator.node.Entries) {
+ iterator.entry = iterator.node.Entries[e+1]
+ goto between
+ }
+ }
+ // Reached leaf node and there are no entries to the right of the current entry, so go up to the parent
+ for iterator.node.Parent != nil {
+ iterator.node = iterator.node.Parent
+ // Find next entry position in current node (note: search returns the first equal or bigger than entry)
+ e, _ := iterator.tree.search(iterator.node, iterator.entry.Key)
+ // Check that there is a next entry position in current node
+ if e < len(iterator.node.Entries) {
+ iterator.entry = iterator.node.Entries[e]
+ goto between
+ }
+ }
+
+end:
+ iterator.End()
+ return false
+
+between:
+ iterator.position = between
+ return true
+}
+
+// Prev moves the iterator to the previous element and returns true if there was a previous element in the container.
+// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value().
+// Modifies the state of the iterator.
+func (iterator *Iterator) Prev() bool {
+ // If already at beginning, go to begin
+ if iterator.position == begin {
+ goto begin
+ }
+ // If at end, get the right-most entry in the tree
+ if iterator.position == end {
+ right := iterator.tree.Right()
+ if right == nil {
+ goto begin
+ }
+ iterator.node = right
+ iterator.entry = right.Entries[len(right.Entries)-1]
+ goto between
+ }
+ {
+ // Find current entry position in current node
+ e, _ := iterator.tree.search(iterator.node, iterator.entry.Key)
+ // Try to go down to the child left of the current entry
+ if e < len(iterator.node.Children) {
+ iterator.node = iterator.node.Children[e]
+ // Try to go down to the child right of the current node
+ for len(iterator.node.Children) > 0 {
+ iterator.node = iterator.node.Children[len(iterator.node.Children)-1]
+ }
+ // Return the right-most entry
+ iterator.entry = iterator.node.Entries[len(iterator.node.Entries)-1]
+ goto between
+ }
+ // Above assures that we have reached a leaf node, so return the previous entry in current node (if any)
+ if e-1 >= 0 {
+ iterator.entry = iterator.node.Entries[e-1]
+ goto between
+ }
+ }
+ // Reached leaf node and there are no entries to the left of the current entry, so go up to the parent
+ for iterator.node.Parent != nil {
+ iterator.node = iterator.node.Parent
+ // Find previous entry position in current node (note: search returns the first equal or bigger than entry)
+ e, _ := iterator.tree.search(iterator.node, iterator.entry.Key)
+ // Check that there is a previous entry position in current node
+ if e-1 >= 0 {
+ iterator.entry = iterator.node.Entries[e-1]
+ goto between
+ }
+ }
+
+begin:
+ iterator.Begin()
+ return false
+
+between:
+ iterator.position = between
+ return true
+}
+
+// Value returns the current element's value.
+// Does not modify the state of the iterator.
+func (iterator *Iterator) Value() interface{} {
+ return iterator.entry.Value
+}
+
+// Key returns the current element's key.
+// Does not modify the state of the iterator.
+func (iterator *Iterator) Key() interface{} {
+ return iterator.entry.Key
+}
+
+// Begin resets the iterator to its initial state (one-before-first)
+// Call Next() to fetch the first element if any.
+func (iterator *Iterator) Begin() {
+ iterator.node = nil
+ iterator.position = begin
+ iterator.entry = nil
+}
+
+// End moves the iterator past the last element (one-past-the-end).
+// Call Prev() to fetch the last element if any.
+func (iterator *Iterator) End() {
+ iterator.node = nil
+ iterator.position = end
+ iterator.entry = nil
+}
+
+// First moves the iterator to the first element and returns true if there was a first element in the container.
+// If First() returns true, then first element's key and value can be retrieved by Key() and Value().
+// Modifies the state of the iterator
+func (iterator *Iterator) First() bool {
+ iterator.Begin()
+ return iterator.Next()
+}
+
+// Last moves the iterator to the last element and returns true if there was a last element in the container.
+// If Last() returns true, then last element's key and value can be retrieved by Key() and Value().
+// Modifies the state of the iterator.
+func (iterator *Iterator) Last() bool {
+ iterator.End()
+ return iterator.Prev()
+}
diff --git a/trees/redblacktree/redblacktree.go b/trees/redblacktree/redblacktree.go
index f79d02b6..a8a496ec 100644
--- a/trees/redblacktree/redblacktree.go
+++ b/trees/redblacktree/redblacktree.go
@@ -13,7 +13,6 @@ package redblacktree
import (
"fmt"
- "github.com/emirpasic/gods/stacks/linkedliststack"
"github.com/emirpasic/gods/trees"
"github.com/emirpasic/gods/utils"
)
@@ -153,8 +152,9 @@ func (tree *Tree) Size() int {
// Keys returns all keys in-order
func (tree *Tree) Keys() []interface{} {
keys := make([]interface{}, tree.size)
- for i, node := range tree.inOrder() {
- keys[i] = node.Key
+ it := tree.Iterator()
+ for i := 0; it.Next(); i++ {
+ keys[i] = it.Key()
}
return keys
}
@@ -162,8 +162,9 @@ func (tree *Tree) Keys() []interface{} {
// Values returns all values in-order based on the key.
func (tree *Tree) Values() []interface{} {
values := make([]interface{}, tree.size)
- for i, node := range tree.inOrder() {
- values[i] = node.Value
+ it := tree.Iterator()
+ for i := 0; it.Next(); i++ {
+ values[i] = it.Value()
}
return values
}
@@ -267,35 +268,6 @@ func (node *Node) String() string {
return fmt.Sprintf("%v", node.Key)
}
-// Returns all nodes in order
-func (tree *Tree) inOrder() []*Node {
- nodes := make([]*Node, tree.size)
- if tree.size > 0 {
- current := tree.Root
- stack := linkedliststack.New()
- done := false
- count := 0
- for !done {
- if current != nil {
- stack.Push(current)
- current = current.Left
- } else {
- if !stack.Empty() {
- currentPop, _ := stack.Pop()
- current = currentPop.(*Node)
- nodes[count] = current
- count++
- current = current.Right
- } else {
- done = true
- }
- }
- }
- }
- return nodes
-}
-
-// String returns a string representation of container
func output(node *Node, prefix string, isTail bool, str *string) {
if node.Right != nil {
newPrefix := prefix
diff --git a/trees/redblacktree/redblacktree_test.go b/trees/redblacktree/redblacktree_test.go
index cdacdeee..714defcf 100644
--- a/trees/redblacktree/redblacktree_test.go
+++ b/trees/redblacktree/redblacktree_test.go
@@ -557,14 +557,155 @@ func TestRedBlackTreeIteratorLast(t *testing.T) {
}
}
-func BenchmarkRedBlackTree(b *testing.B) {
+func benchmarkGet(b *testing.B, tree *Tree, size int) {
for i := 0; i < b.N; i++ {
- tree := NewWithIntComparator()
- for n := 0; n < 1000; n++ {
- tree.Put(n, n)
+ for n := 0; n < size; n++ {
+ tree.Get(n)
}
- for n := 0; n < 1000; n++ {
+ }
+}
+
+func benchmarkPut(b *testing.B, tree *Tree, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ }
+}
+
+func benchmarkRemove(b *testing.B, tree *Tree, size int) {
+ for i := 0; i < b.N; i++ {
+ for n := 0; n < size; n++ {
tree.Remove(n)
}
}
}
+
+func BenchmarkRedBlackTreeGet100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeGet1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeGet10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeGet100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkGet(b, tree, size)
+}
+
+func BenchmarkRedBlackTreePut100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator()
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkRedBlackTreePut1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkRedBlackTreePut10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkRedBlackTreePut100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkPut(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeRemove100(b *testing.B) {
+ b.StopTimer()
+ size := 100
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeRemove1000(b *testing.B) {
+ b.StopTimer()
+ size := 1000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeRemove10000(b *testing.B) {
+ b.StopTimer()
+ size := 10000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}
+
+func BenchmarkRedBlackTreeRemove100000(b *testing.B) {
+ b.StopTimer()
+ size := 100000
+ tree := NewWithIntComparator()
+ for n := 0; n < size; n++ {
+ tree.Put(n, struct{}{})
+ }
+ b.StartTimer()
+ benchmarkRemove(b, tree, size)
+}