您的位置:首页 > 编程语言 > Go语言

Go实现二叉查找树

2018-02-24 15:35 225 查看
-----------------------------------------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()
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二叉查找树 Go