-----------------------------------------binarysearchtree.go----------------------------------------
package binarysearchtree import ( "fmt" "container/list" "errors" ) var ( ErrComparatorIsNil = errors.New("comparator of BinarySearchTree is nil") ErrTreeIsEmpty = errors.New("BinarySearchTree is empty") ) type ( Comparator interface { Compare(x interface{}, y *BinaryNode) int } BinaryNode struct { Val interface{} Left, Right *BinaryNode } BinarySearchTree struct { Root *BinaryNode Comparator Comparator } ) // 創建二叉搜索樹時必須提供排序規則 func New(comparator Comparator) *BinarySearchTree { if comparator == nil { panic(ErrComparatorIsNil) } return &BinarySearchTree{nil, comparator} } // 清空數據 func (tree *BinarySearchTree) MakeEmpty() { tree.Root = nil } func (tree *BinarySearchTree) IsEmpty() bool { return tree.Root == nil } func (tree *BinarySearchTree) Contains(x interface{}) (bool, error) { return tree.contains(x, tree.Root) } // 遞歸查找是否包含某值 func (tree *BinarySearchTree) contains(x interface{}, root *BinaryNode) (bool, error) { if root == nil { return false, nil } if tree.Comparator == nil { return false, ErrComparatorIsNil } compareResult := tree.Comparator.Compare(x, root) if compareResult < 0 { return tree.contains(x, root.Left) } else if compareResult > 0 { return tree.contains(x, root.Right) } else { return true, nil } } // 遞歸查找最小值 最小值只能在左子樹上,因此只需要遞歸左子樹即可 func (tree *BinarySearchTree) FindMin() (*BinaryNode, error) { if tree.IsEmpty() { return nil, ErrTreeIsEmpty } return tree.findMin(tree.Root), nil } func (tree *BinarySearchTree) findMin(root *BinaryNode) *BinaryNode { if root == nil { return nil } else if root.Left == nil { return root } return tree.findMin(root.Left) } // 使用非遞歸的方式查找最大值 最大值只能在右子樹上的最後的葉子節點 func (tree *BinarySearchTree) FindMax() (*BinaryNode, error) { if tree.IsEmpty() { return nil, ErrTreeIsEmpty } root := tree.Root for ; root.Right != nil; { root = root.Right } return root, nil } // 插入值val 同contains方法一樣遍歷樹,如果找到相同的值不做任何操作,如果比當前節點值大,遞歸其插入左子樹,否則插入又子樹 func (tree *BinarySearchTree) Insert(val interface{}) { tree.Root = tree.insert(val, tree.Root) } func (tree *BinarySearchTree) insert(val interface{}, root *BinaryNode) *BinaryNode { if root == nil { return &BinaryNode{val, nil, nil} } compareResult := tree.Comparator.Compare(val, root) if compareResult < 0 { root.Left = tree.insert(val, root.Left) } else if compareResult > 0 { root.Right = tree.insert(val, root.Right) } else { //重複值,不做操作 } return root } // 刪除操作最爲複雜 // 先遞歸查找到要刪除的元素 // 然後分爲:葉子節點,左子樹爲nil,右子樹爲nil,左右均不爲nil四種情況 func (tree *BinarySearchTree) Remove(val interface{}) *BinaryNode { return tree.remove(val, tree.Root, nil) } func (tree *BinarySearchTree) remove(val interface{}, root, parent *BinaryNode) (*BinaryNode) { if root == nil { return nil } compareResult := tree.Comparator.Compare(val, root) if compareResult < 0 { return tree.remove(val, root.Left, root) } else if compareResult > 0 { return tree.remove(val, root.Right, root) } else { ret := &BinaryNode{Val: root.Val} // 左右子樹有任意一個爲空,用另外一個替換掉當前節點即可 if root.Left == nil { tree.replaceChild(parent, val, root.Right) return ret } if root.Right == nil { tree.replaceChild(parent, val, root.Left) return ret } // 左右子樹均不爲空,則將右子樹中的最小值替換當前節點,並從又子樹中刪掉該最小值即可 rightMin := tree.findMin(root.Right) root.Val = rightMin.Val tree.replaceChild(root.Right, rightMin.Val, rightMin.Right) return ret } } // 給定的值是左子節點的值,則替換左節點,否則替換右節點 func (tree *BinarySearchTree) replaceChild(parent *BinaryNode, oldVal interface{}, theNode *BinaryNode) { if parent == nil { return } if tree.Comparator.Compare(oldVal, parent.Left) == 0 { parent.Left = theNode } else { parent.Right = theNode } } // 層序遍歷輸出 func (tree *BinarySearchTree) Print() { if tree.IsEmpty() { return } // 使用go官方包裏的list模擬隊列的操作 l := list.New() l.PushBack(tree.Root) for ; l.Len() > 0; { element := l.Front() l.Remove(element) if node, ok := element.Value.(*BinaryNode); ok && node != nil { l.PushBack(node.Left) l.PushBack(node.Right) fmt.Printf("%v\t", node.Val) } } }
-------------------------------------binarysearchtree_test.go-------------------------------------
package binarysearchtree import ( "testing" "fmt" ) type IntComparator struct { } func (this IntComparator) Compare(x interface{}, y *BinaryNode) int { if y == nil { if x == nil { return 0 } else { return 1 } } if x == nil { return -1 } return x.(int) - y.Val.(int) } func TestBinarySearchTree(t *testing.T) { tree := New(IntComparator{}) tree.Insert(6) tree.Insert(2) tree.Insert(8) tree.Insert(1) tree.Insert(4) tree.Insert(3) tree.Remove(2) fmt.Println(tree.Contains(4)) tree.Print() }