R bst_example_test.go => benchmark_binarysearchtree_traversal_test.go +12 -67
@@ 1,12 1,12 @@
package algorithms_test
import (
- "fmt"
+ "testing"
"git.sr.ht/~telemachus/algorithms"
)
-func ExampleInOrderWalk() {
+func BenchmarkInOrderIterativeWalk(b *testing.B) {
t := algorithms.NewBST()
t.Insert(15)
t.Insert(6)
@@ 19,60 19,16 @@ func ExampleInOrderWalk() {
t.Insert(9)
t.Insert(17)
t.Insert(20)
-
show := func(i int) {
- fmt.Printf("%d\n", i)
+ return
}
-
- t.InOrderWalk(show)
- // Output:
- // 2
- // 3
- // 4
- // 6
- // 7
- // 9
- // 13
- // 15
- // 17
- // 18
- // 20
-}
-
-func ExamplePreOrderWalk() {
- t := algorithms.NewBST()
- t.Insert(15)
- t.Insert(6)
- t.Insert(18)
- t.Insert(3)
- t.Insert(2)
- t.Insert(4)
- t.Insert(7)
- t.Insert(13)
- t.Insert(9)
- t.Insert(17)
- t.Insert(20)
-
- show := func(i int) {
- fmt.Printf("%d\n", i)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ t.InOrderIterativeWalk(show)
}
-
- t.PreOrderWalk(show)
- // Output:
- // 15
- // 6
- // 3
- // 2
- // 4
- // 7
- // 13
- // 9
- // 18
- // 17
- // 20
}
-func ExamplePostOrderWalk() {
+func BenchmarkInOrderRecursiveWalk(b *testing.B) {
t := algorithms.NewBST()
t.Insert(15)
t.Insert(6)
@@ 85,22 41,11 @@ func ExamplePostOrderWalk() {
t.Insert(9)
t.Insert(17)
t.Insert(20)
-
show := func(i int) {
- fmt.Printf("%d\n", i)
+ return
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ t.InOrderWalk(show)
}
-
- t.PostOrderWalk(show)
- // Output:
- // 2
- // 4
- // 3
- // 9
- // 13
- // 7
- // 6
- // 17
- // 20
- // 18
- // 15
}
M binarysearchtree.go => binarysearchtree.go +217 -12
@@ 8,6 8,14 @@ type Node struct {
value int
}
+func (n *Node) Value() int {
+ return n.value
+}
+
+func (n *Node) Count() int {
+ return n.count
+}
+
type Tree struct {
root *Node
size int
@@ 24,11 32,9 @@ func (t *Tree) Size() int {
}
func (t *Tree) Insert(v int) {
- var prevNode *Node
- currNode := t.root
-
// Walk the tree until we find a spot to insert a new node.
- for currNode != nil {
+ var prevNode *Node
+ for currNode := t.root; currNode != nil; {
prevNode = currNode
switch {
case v < currNode.value:
@@ 43,7 49,7 @@ func (t *Tree) Insert(v int) {
}
// Create a new node, place it, and increase the size of the tree.
- newNode := &Node{value: v, parent: prevNode}
+ newNode := &Node{value: v, parent: prevNode, count: 1}
switch {
case prevNode == nil:
t.root = newNode
@@ 60,9 66,11 @@ func (t *Tree) InOrderWalk(f fn) {
return
}
t.root.left.inOrderWalk(f)
- f(t.root.value)
+ for i := t.root.count; i > 0; i-- {
+ f(t.root.value)
+ }
t.root.right.inOrderWalk(f)
-
+
}
func (n *Node) inOrderWalk(f fn) {
@@ 70,7 78,9 @@ func (n *Node) inOrderWalk(f fn) {
return
}
n.left.inOrderWalk(f)
- f(n.value)
+ for i := n.count; i > 0; i-- {
+ f(n.value)
+ }
n.right.inOrderWalk(f)
}
@@ 78,7 88,9 @@ func (t *Tree) PreOrderWalk(f fn) {
if t == nil {
return
}
- f(t.root.value)
+ for i := t.root.count; i > 0; i-- {
+ f(t.root.value)
+ }
t.root.left.preOrderWalk(f)
t.root.right.preOrderWalk(f)
}
@@ 87,7 99,9 @@ func (n *Node) preOrderWalk(f fn) {
if n == nil {
return
}
- f(n.value)
+ for i := n.count; i > 0; i-- {
+ f(n.value)
+ }
n.left.preOrderWalk(f)
n.right.preOrderWalk(f)
}
@@ 98,7 112,9 @@ func (t *Tree) PostOrderWalk(f fn) {
}
t.root.left.postOrderWalk(f)
t.root.right.postOrderWalk(f)
- f(t.root.value)
+ for i := t.root.count; i > 0; i-- {
+ f(t.root.value)
+ }
}
func (n *Node) postOrderWalk(f fn) {
@@ 107,5 123,194 @@ func (n *Node) postOrderWalk(f fn) {
}
n.left.postOrderWalk(f)
n.right.postOrderWalk(f)
- f(n.value)
+ for i := n.count; i > 0; i-- {
+ f(n.value)
+ }
+}
+
+func (t *Tree) InOrderIterativeWalk(f fn) {
+ if node := t.root; node != nil {
+ for node.left != nil {
+ node = node.left
+ }
+ for node != nil {
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ if node.right != nil {
+ node = node.right
+ for node.left != nil {
+ node = node.left
+ }
+ } else {
+ for node.parent != nil && node.parent.right == node {
+ node = node.parent
+ }
+ node = node.parent
+ }
+ }
+ }
+}
+
+func (t *Tree) PreOrderIterativeWalk(f fn) {
+ if node := t.root; node != nil {
+ for node.left != nil {
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ node = node.left
+ }
+ f(node.value)
+ for node != nil {
+ if node.right != nil {
+ node = node.right
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ for node.left != nil {
+ node = node.left
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ }
+ } else {
+ for node.parent != nil && node.parent.right == node {
+ node = node.parent
+ }
+ node = node.parent
+ }
+ }
+ }
+}
+
+func (t *Tree) PostOrderIterativeWalk(f fn) {
+ if node := t.root; node != nil {
+ for node.left != nil {
+ node = node.left
+ }
+ for node != nil {
+ if node.right != nil {
+ node = node.right
+ for node.left != nil {
+ node = node.left
+ }
+ } else {
+ for node.parent != nil && node.parent.right == node {
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ node = node.parent
+ }
+ for i := node.count; i > 0; i-- {
+ f(node.value)
+ }
+ node = node.parent
+ }
+ }
+ }
+}
+
+func (t *Tree) Search(v int) *Node {
+ return t.root.search(v)
+}
+
+func (n *Node) search(v int) *Node {
+ for n != nil && v != n.value {
+ switch {
+ case v < n.value:
+ n = n.left
+ case v > n.value:
+ n = n.right
+ }
+ }
+ return n
+}
+
+func (t *Tree) Min() *Node {
+ return t.root.min()
+}
+
+func (n *Node) min() *Node {
+ for n.left != nil {
+ n = n.left
+ }
+ return n
+}
+
+func (t *Tree) Max() *Node {
+ return t.root.max()
+}
+
+func (n *Node) max() *Node {
+ for n.right != nil {
+ n = n.right
+ }
+ return n
+}
+
+func (t *Tree) Successor(currNode *Node) *Node {
+ if currNode.right != nil {
+ return currNode.right.min()
+ }
+
+ prevNode := currNode.parent
+ for prevNode != nil && currNode == prevNode.right {
+ currNode = prevNode
+ prevNode = prevNode.parent
+ }
+ return prevNode
+}
+
+func (t *Tree) Predecessor(currNode *Node) *Node {
+ if currNode.left != nil {
+ return currNode.left.max()
+ }
+
+ prevNode := currNode.parent
+ for prevNode != nil && currNode == prevNode.left {
+ currNode = prevNode
+ prevNode = prevNode.parent
+ }
+ return prevNode
+}
+
+func (t *Tree) Delete(v int) {
+ deadNode := t.Search(v)
+ if deadNode == nil {
+ return
+ }
+
+ switch {
+ case deadNode.count > 1:
+ deadNode.count--
+ case deadNode.left == nil:
+ t.transplant(deadNode, deadNode.right)
+ case deadNode.right == nil:
+ t.transplant(deadNode, deadNode.left)
+ default:
+ succNode := deadNode.right.min()
+ if succNode.parent != deadNode {
+ t.transplant(succNode, succNode.right)
+ succNode.right = deadNode.right
+ succNode.right.parent = succNode
+ }
+ t.transplant(deadNode, succNode)
+ succNode.left = deadNode.left
+ succNode.left.parent = succNode
+ }
+ t.size--
+}
+
+func (t *Tree) transplant(deadNode, succNode *Node) {
+ switch {
+ case deadNode.parent == nil:
+ t.root = succNode
+ case deadNode == deadNode.parent.left:
+ deadNode.parent.left = succNode
+ default:
+ deadNode.parent.right = succNode
+ }
+ if succNode != nil {
+ succNode.parent = deadNode.parent
+ }
}
A binarysearchtree_example_test.go => binarysearchtree_example_test.go +260 -0
@@ 0,0 1,260 @@
+package algorithms_test
+
+import (
+ "fmt"
+
+ "git.sr.ht/~telemachus/algorithms"
+)
+
+func makeTree() *algorithms.Tree {
+ t := algorithms.NewBST()
+ t.Insert(15)
+ t.Insert(6)
+ t.Insert(18)
+ t.Insert(3)
+ t.Insert(2)
+ t.Insert(4)
+ t.Insert(7)
+ t.Insert(13)
+ t.Insert(9)
+ t.Insert(17)
+ t.Insert(20)
+ t.Insert(7)
+ return t
+}
+
+func show(i int) {
+ fmt.Println(i)
+}
+
+func ExampleInOrderWalk() {
+ t := makeTree()
+ t.InOrderWalk(show)
+ // Output:
+ // 2
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 15
+ // 17
+ // 18
+ // 20
+}
+
+func ExampleInOrderIterativeWalk() {
+ t := makeTree()
+ t.InOrderIterativeWalk(show)
+ // Output:
+ // 2
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 15
+ // 17
+ // 18
+ // 20
+}
+
+func ExamplePreOrderWalk() {
+ t := makeTree()
+ t.PreOrderWalk(show)
+ // Output:
+ // 15
+ // 6
+ // 3
+ // 2
+ // 4
+ // 7
+ // 7
+ // 13
+ // 9
+ // 18
+ // 17
+ // 20
+}
+
+func ExamplePreOrderIterativeWalk() {
+ t := makeTree()
+ t.PreOrderIterativeWalk(show)
+ // Output:
+ // 15
+ // 6
+ // 3
+ // 2
+ // 4
+ // 7
+ // 7
+ // 13
+ // 9
+ // 18
+ // 17
+ // 20
+}
+
+func ExamplePostOrderWalk() {
+ t := makeTree()
+ t.PostOrderWalk(show)
+ // Output:
+ // 2
+ // 4
+ // 3
+ // 9
+ // 13
+ // 7
+ // 7
+ // 6
+ // 17
+ // 20
+ // 18
+ // 15
+}
+
+func ExamplePostOrderIterativeWalk() {
+ t := makeTree()
+ t.PostOrderIterativeWalk(show)
+ // Output:
+ // 2
+ // 4
+ // 3
+ // 9
+ // 13
+ // 7
+ // 7
+ // 6
+ // 17
+ // 20
+ // 18
+ // 15
+}
+
+func ExampleDeleteNoChildren() {
+ t := makeTree()
+ t.Delete(2)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 11
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 15
+ // 17
+ // 18
+ // 20
+}
+
+func ExampleDeleteRoot() {
+ t := makeTree()
+ t.Delete(15)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 11
+ // 2
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 17
+ // 18
+ // 20
+}
+
+func ExampleDeleteTwoChildren() {
+ t := makeTree()
+ t.Delete(18)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 11
+ // 2
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 15
+ // 17
+ // 20
+}
+
+func ExampleDeleteLeftChildOnly() {
+ t := makeTree()
+ t.Delete(13)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 11
+ // 2
+ // 3
+ // 4
+ // 6
+ // 7
+ // 7
+ // 9
+ // 15
+ // 17
+ // 18
+ // 20
+}
+
+func ExampleDeleteRightChildOnly() {
+ t := makeTree()
+ t.Insert(5)
+ t.Delete(4)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 12
+ // 2
+ // 3
+ // 5
+ // 6
+ // 7
+ // 7
+ // 9
+ // 13
+ // 15
+ // 17
+ // 18
+ // 20
+}
+
+func ExampleDeleteMultipleItemsOfAllkinds() {
+ t := makeTree()
+ t.Insert(5)
+ t.Delete(4)
+ t.Delete(13)
+ t.Delete(15)
+ fmt.Println(t.Size())
+ t.InOrderWalk(show)
+ // Output:
+ // 10
+ // 2
+ // 3
+ // 5
+ // 6
+ // 7
+ // 7
+ // 9
+ // 17
+ // 18
+ // 20
+}
M binarysearchtree_test.go => binarysearchtree_test.go +118 -2
@@ 25,12 25,128 @@ func TestNewBST(t *testing.T) {
func TestTreeInsert(t *testing.T) {
tree := algorithms.NewBST()
-
tree.Insert(2)
tree.Insert(10)
tree.Insert(-15)
+ tree.Insert(10)
- if 3 != tree.Size() {
+ if 4 != tree.Size() {
t.Errorf("inserted three items; actual tree.Size() is %d", tree.Size())
}
}
+
+func TestTreeSearch(t *testing.T) {
+ tree := algorithms.NewBST()
+ tree.Insert(2)
+ tree.Insert(10)
+ tree.Insert(-15)
+ tree.Insert(10)
+
+ actual := tree.Search(-15)
+ if -15 != actual.Value() {
+ t.Errorf("expected %d; actual %d", -15, actual.Value())
+ }
+
+ actual = tree.Search(7)
+ if nil != actual {
+ t.Errorf("expected %#v; actual %#v", nil, actual)
+ }
+
+ actual = tree.Search(10)
+ if 2 != actual.Count() {
+ t.Errorf("expected result to have 10 twice; actual %d", actual.Count())
+ }
+}
+
+func TestTreeMin(t *testing.T) {
+ tree := algorithms.NewBST()
+ tree.Insert(2)
+ tree.Insert(10)
+ tree.Insert(-15)
+ tree.Insert(10)
+
+ actual := tree.Min()
+ if -15 != actual.Value() {
+ t.Errorf("expected a minimum of %d; actual %d", -15, actual.Value())
+ }
+}
+
+func TestTreeMax(t *testing.T) {
+ tree := algorithms.NewBST()
+ tree.Insert(2)
+ tree.Insert(10)
+ tree.Insert(-15)
+ tree.Insert(10)
+ tree.Insert(1010)
+
+ actual := tree.Max()
+ if 1010 != actual.Value() {
+ t.Errorf("expected a maximum of %d; actual %d", 1010, actual.Value())
+ }
+}
+
+func TestTreeSuccessor(t *testing.T) {
+ tree := algorithms.NewBST()
+ tree.Insert(15)
+ tree.Insert(6)
+ tree.Insert(3)
+ tree.Insert(2)
+ tree.Insert(4)
+ tree.Insert(7)
+ tree.Insert(13)
+ tree.Insert(9)
+ tree.Insert(18)
+ tree.Insert(17)
+ tree.Insert(20)
+
+ node := tree.Search(7)
+ actual := tree.Successor(node)
+ if 9 != actual.Value() {
+ t.Errorf("expected 9 as successor; actual %d", actual.Value())
+ }
+
+ node = tree.Search(20)
+ actual = tree.Successor(node)
+ if nil != actual {
+ t.Errorf("expected nil as successor; actual %#v", actual)
+ }
+}
+
+func TestTreePredecessor(t *testing.T) {
+ tree := algorithms.NewBST()
+ tree.Insert(15)
+ tree.Insert(6)
+ tree.Insert(3)
+ tree.Insert(2)
+ tree.Insert(4)
+ tree.Insert(7)
+ tree.Insert(13)
+ tree.Insert(9)
+ tree.Insert(18)
+ tree.Insert(17)
+ tree.Insert(20)
+
+ node := tree.Search(15)
+ actual := tree.Predecessor(node)
+ if 13 != actual.Value() {
+ t.Errorf("expected 15 as predecessor; actual %d", actual.Value())
+ }
+
+ node = tree.Search(4)
+ actual = tree.Predecessor(node)
+ if 3 != actual.Value() {
+ t.Errorf("expected 3 as predecessor; actual %d", actual.Value())
+ }
+
+ node = tree.Search(9)
+ actual = tree.Predecessor(node)
+ if 7 != actual.Value() {
+ t.Errorf("expected 7 as predecessor; actual %d", actual.Value())
+ }
+
+ node = tree.Search(2)
+ actual = tree.Predecessor(node)
+ if nil != actual {
+ t.Errorf("expected nil as predecessor; actual %#v", actual)
+ }
+}