二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。
二叉查找树的查找操作
先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。
二叉查找树的插入操作
新插入的数据一般都是在叶子节点上,所以我们只需要从根节点开始,依次比较要插入的数据和节点的大小关系。
如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。
二叉查找树的删除操作
第一种情况是,如果要删除的节点没有子节点,我们只需要直接将父节点中,指向要删除节点的指针置为 null。比如图中的删除节点 55。
第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。比如图中的删除节点 13。
第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节点(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。比如图中的删除节点 18。
在二叉查找树中,查找、插入、删除等很多操作的时间复杂度都跟树的高度成正比。两个极端情况的时间复杂度分别是 O(n) 和 O(logn),分别对应二叉树退化成链表的情况和完全二叉树。
存在重复数据的二叉查找树的两种构建方法:一种是让每个节点存储多个值相同的数据;另一种是,每个节点中存储一个数据。
每个节点仍然只存储一个数据。在查找插入位置的过程中,如果碰到一个节点的值,与要插入数据的值相同,我们就将这个要插入的数据放到这个节点的右子树,也就是说,把这个新插入的数据当作大于这个节点的值来处理。
当要查找数据的时候,遇到值相同的节点,我们并不停止查找操作,而是继续在右子树中查找,直到遇到叶子节点,才停止。这样就可以把键值等于要查找值的所有节点都找出来。
对于删除操作,我们也需要先查找到每个要删除的节点,然后再按前面讲的删除操作的方法,依次删除。

BinarySearchTree.go
package _4_tree
type BST struct {
*BinaryTree
//比对函数,0:v==nodeV,正数:v>nodeV,负数:v<nodeV
compareFunc func(v, nodeV interface{}) int
}
func NewBST(rootV interface{}, compareFunc func(v, nodeV interface{}) int) *BST {
if nil == compareFunc {
return nil
}
return &BST{BinaryTree: NewBinaryTree(rootV), compareFunc: compareFunc}
}
func (this *BST) Find(v interface{}) *Node {
p := this.root
for nil != p {
compareResult := this.compareFunc(v, p.data)
if compareResult == 0 {
return p
} else if compareResult > 0 { //v > nodeV
p = p.right
} else { //v < nodeV
p = p.left
}
}
return nil
}
func (this *BST) Insert(v interface{}) bool {
p := this.root
for nil != p {
compareResult := this.compareFunc(v, p.data)
if compareResult == 0 {
return false
} else if compareResult > 0 {
if nil == p.right {
p.right = NewNode(v)
break
}
p = p.right
} else {
if nil == p.left {
p.left = NewNode(v)
break
}
p = p.left
}
}
return true
}
func (this *BST) Delete(v interface{}) bool {
var pp *Node = nil
p := this.root
deleteLeft := false
for nil != p {
compareResult := this.compareFunc(v, p.data)
if compareResult > 0 {
pp = p
p = p.right
deleteLeft = false
} else if compareResult < 0 {
pp = p
p = p.left
deleteLeft = true
} else {
break
}
}
if nil == p { //需要删除的节点不存在
return false
} else if nil == p.left && nil == p.right { //删除的是一个叶子节点
if nil != pp {
if deleteLeft {
pp.left = nil
} else {
pp.right = nil
}
} else { //根节点
this.root = nil
}
} else if nil != p.right { //删除的是一个有右孩子,不一定有左孩子的节点
//找到p节点右孩子的最小节点
pq := p
q := p.right //向右走一步
fromRight := true
for nil != q.left { //向左走到底
pq = q
q = q.left
fromRight = false
}
if fromRight {
//pq.right = nil
pq.right = p.right
} else {
pq.left = nil
}
q.left = p.left
q.right = p.right
if nil == pp { //根节点被删除
this.root = q
} else {
if deleteLeft {
//pq.left = q
pp.left = q
} else {
//pq.right = q
pp.right = q
}
}
} else { //删除的是一个只有左孩子的节点
if nil != pp {
if deleteLeft {
pp.left = p.left
} else {
pp.right = p.left
}
} else {
if deleteLeft {
this.root = p.left
} else {
this.root = p.left
}
}
}
return true
}
func (this *BST) Min() *Node {
p := this.root
for nil != p.left {
p = p.left
}
return p
}
func (this *BST) Max() *Node {
p := this.root
for nil != p.right {
p = p.right
}
return p
}
BinaryTree.go
package _4_tree
import "fmt"
type BinaryTree struct {
root *Node
}
func NewBinaryTree(rootV interface{}) *BinaryTree {
return &BinaryTree{NewNode(rootV)}
}
func (this *BinaryTree) InOrderTraverse() {
p := this.root
s := NewArrayStack()
for !s.IsEmpty() || nil != p {
if nil != p {
s.Push(p)
p = p.left
} else {
tmp := s.Pop().(*Node)
fmt.Printf("%+v ", tmp.data)
p = tmp.right
}
}
fmt.Println()
}
func (this *BinaryTree) PreOrderTraverse() {
p := this.root
s := NewArrayStack()
for !s.IsEmpty() || nil != p {
if nil != p {
fmt.Printf("%+v ", p.data)
s.Push(p)
p = p.left
} else {
p = s.Pop().(*Node).right
}
}
fmt.Println()
}
func (this *BinaryTree) PostOrderTraverse() {
s1 := NewArrayStack()
s2 := NewArrayStack()
s1.Push(this.root)
for !s1.IsEmpty() {
p := s1.Pop().(*Node)
s2.Push(p)
if nil != p.left {
s1.Push(p.left)
}
if nil != p.right {
s1.Push(p.right)
}
}
for !s2.IsEmpty() {
fmt.Printf("%+v ", s2.Pop().(*Node).data)
}
}
//use one stack, pre cursor to traverse from post order
func (this *BinaryTree) PostOrderTraverse2() {
r := this.root
s := NewArrayStack()
//point to last visit node
var pre *Node
s.Push(r)
for !s.IsEmpty() {
r = s.Top().(*Node)
if (r.left == nil && r.right == nil) ||
(pre != nil && (pre == r.left || pre == r.right)) {
fmt.Printf("%+v ", r.data)
s.Pop()
pre = r
} else {
if r.right != nil {
s.Push(r.right)
}
if r.left != nil {
s.Push(r.left)
}
}
}
}
TreeNode.go
package _4_tree
import "fmt"
type Node struct {
data interface{}
left *Node
right *Node
}
func NewNode(data interface{}) *Node {
return &Node{data: data}
}
func (this *Node) String() string {
return fmt.Sprintf("v:%+v, left:%+v, right:%+v", this.data, this.left, this.right)
}
StackBasedOnArray.go
package _4_tree
import "fmt"
/*
基于数组实现的栈
*/
type ArrayStack struct {
//数据
data []interface{}
//栈顶指针
top int
}
func NewArrayStack() *ArrayStack {
return &ArrayStack{
data: make([]interface{}, 0, 32),
top: -1,
}
}
func (this *ArrayStack) IsEmpty() bool {
if this.top < 0 {
return true
}
return false
}
func (this *ArrayStack) Push(v interface{}) {
if this.top < 0 {
this.top = 0
} else {
this.top += 1
}
if this.top > len(this.data)-1 {
this.data = append(this.data, v)
} else {
this.data[this.top] = v
}
}
func (this *ArrayStack) Pop() interface{} {
if this.IsEmpty() {
return nil
}
v := this.data[this.top]
this.top -= 1
return v
}
func (this *ArrayStack) Top() interface{} {
if this.IsEmpty() {
return nil
}
return this.data[this.top]
}
func (this *ArrayStack) Flush() {
this.top = -1
}
func (this *ArrayStack) Print() {
if this.IsEmpty() {
fmt.Println("empty statck")
} else {
for i := this.top; i >= 0; i-- {
fmt.Println(this.data[i])
}
}
}
以上内容摘自《数据结构与算法之美》课程,来学习更多精彩内容吧。


1835

被折叠的 条评论
为什么被折叠?



