Go 数据结构--二分查找树
今天开始一个Go实现常见数据结构的系列吧。有时间会更新其他数据结构。
一些概念
二叉树:二叉树是每个节点最多有两个子树的树结构。
完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
满二叉树:除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
平衡二叉树:平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉查找树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
二叉搜索树原理
二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构。中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,O(log(n)).
实现
上述基本是百度百科的概念,现在来直接上实现代码:
/*
时间:2017/8/24
功能:二叉树
*/
package main
import (
"fmt"
"sync"
)
//二叉树节点结构
type Node struct {
data int
left *Node
right *Node
}
//二叉查找树结构
type BST struct {
root *Node
lock sync.RWMutex
}
//插入方法(判断位置 中序遍历)
func insertNode(node *Node, addNode *Node) {
if addNode.data < node.data {
if node.left == nil {
node.left = addNode
} else {
insertNode(node.left, addNode)
}
} else {
if node.right == nil {
node.right = addNode
} else {
insertNode(node.right, addNode)
}
}
}
//插入操作
func (t *BST) Insert(data int) {
t.lock.Lock()
defer t.lock.Unlock()
node := &Node{
data: data,
left: nil,
right: nil,
}
if t.root == nil {
t.root = node
} else {
insertNode(t.root, node)
}
}
//先序遍历
func PreOrderTraverse(bst *Node) {
if bst != nil {
fmt.Printf("%d ", bst.data)
PreOrderTraverse(bst.left)
PreOrderTraverse(bst.right)
}
}
//中序遍历
func InOrderTraverse(bst *Node) {
if bst != nil {
InOrderTraverse(bst.left)
fmt.Printf("%d ", bst.data)
InOrderTraverse(bst.right)
}
}
//后序遍历
func PostOrderTraverse(bst *Node) {
if bst != nil {
PostOrderTraverse(bst.left)
PostOrderTraverse(bst.right)
fmt.Printf("%d ", bst.data)
}
}
//查找
func SearchBST(node *Node, key int) bool {
if node == nil {
return false
}
if key == node.data {
return true
}
if key < node.data {
return SearchBST(node.left, key)
} else {
return SearchBST(node.right, key)
}
}
//删除执行函数
func remove(node *Node, key int) *Node {
if node == nil {
return nil
}
if key == node.data {
if node.left == nil && node.right == nil {
node = nil
return nil
}
if node.left == nil {
node = node.right
return node
}
if node.right == nil {
node = node.left
return node
}
rightside := node.right
for {
if rightside != nil && rightside.left != nil {
rightside = rightside.left
} else {
break
}
}
node.data = rightside.data
node.right = remove(node.right, node.data)
return node
}
if key < node.data {
node.left = remove(node.left, key)
return node
} else {
node.right = remove(node.right, key)
return node
}
}
//删除操作
func (t *BST) Remove(key int) {
t.lock.Lock()
defer t.lock.Unlock()
remove(t.root, key)
}
func main() {
var t BST
t.Insert(2)
t.Insert(6)
t.Insert(5)
t.Insert(1)
t.Insert(10)
t.Insert(8)
fmt.Println("PREORDER...")
PreOrderTraverse(t.root)
fmt.Println("\nINORDER...")
InOrderTraverse(t.root)
fmt.Println("\nPOSTORDER...")
PostOrderTraverse(t.root)
fmt.Printf("\n")
fmt.Println("Search...")
fmt.Println(SearchBST(t.root, 6))
fmt.Println("Remove...")
t.Remove(6)
fmt.Println("PREORDER...")
PreOrderTraverse(t.root)
fmt.Println("\nINORDER...")
InOrderTraverse(t.root)
fmt.Println("\nPOSTORDER...")
PostOrderTraverse(t.root)
fmt.Printf("\n")
fmt.Println("Search...")
fmt.Println(SearchBST(t.root, 6))
}
执行结果
PREORDER...
2 1 6 5 10 8
INORDER...
1 2 5 6 8 10
POSTORDER...
1 5 8 10 6 2
Search...
true
Remove...
PREORDER...
2 1 8 5 10
INORDER...
1 2 5 8 10
POSTORDER...
1 5 10 8 2
Search...
false
总结
照例得总结一波,其实每什么好总结的,大家都熟悉的数据结构。在增删查的复杂度比较均衡。拿来练手非常不错。
|
请发表评论