Go實現二叉查找樹

-----------------------------------------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()
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章