~telemachus/algorithms

170f30968d79f8e123a874f6bd01ceb5cd3c1ee8 — Peter Aronoff 9 months ago 7efe7ef
Finish initial binary search tree implementation
4 files changed, 607 insertions(+), 81 deletions(-)

R bst_example_test.go => benchmark_binarysearchtree_traversal_test.go
M binarysearchtree.go
A binarysearchtree_example_test.go
M binarysearchtree_test.go
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)
	}
}