二叉排序树要么是空二叉树 ,要么具有如下特点:
如下图就是一个二叉排序树:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VsGloKcV-1642763317481)(C:\Users\86186\AppData\Roaming\Typora\typora-user-images\image-20220117113147858.png)]
再二叉排序树中,进行查找,效率非常高,查找过程如下:
查找的特点:
再搜索到,位置后,就可以直接插入,插入效率为查找效率。
假设要删除的为结点 p,则对于二叉排序树来说,需要根据结点 p 所在不同的位置作不同的操作,有以下 3 种可能:
1、结点 p 为叶子结点,此时只需要删除该结点,并修改其双亲结点的指针即可;
2、结点 p 只有左子树或者只有右子树,如果 p 是其双亲节点的左孩子,则直接将 p 节点的左子树或右子树作为其双亲节点的左子树;反之也是如此,如果 p 是其双亲节点的右孩子,则直接将 p 节点的左子树或右子树作为其双亲节点的右子树;
3、结点 p 左右子树都有,此时有两种处理方式:
1)令结点 p 的左子树为其双亲结点的左子树;结点 p 的右子树为其自身直接前驱结点的右子树,如图 3 所示;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TU3giAgM-1642763317484)(D:\文档\数据结构与算法\image\image-20220117114137245.png)]
2)用结点 p 的直接前驱(或直接后继)来代替结点 p,同时在二叉排序树中对其直接前驱(或直接后继)做删除操作。如图 4 为使用直接前驱代替结点 p:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yAdjbKN-1642763317485)(D:\文档\数据结构与算法\image\image-20220117114223810.png)]
二叉树查找的时间复杂度,不是固定的,和构造时,关键字的顺序有很大关系。
最坏的情况,如果关键字都是拍好序的。如12,24,37,45,53,93,这样一个完全有序的集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2794VL8a-1642763317486)(D:\文档\数据结构与算法\image\image-20220117115112614.png)]
二叉树,就会被构造成一条线,这时时间复杂度就会变成,O(n).
有没有,既有二叉树的有点,添加元素时,有一直是平滑的数据结构呢?
平衡二叉树基于 二叉排序树。
大家知道如果,如果建立查找二叉树,的序列是随机的,二叉树的查找性能会接近 O(logn) ,但是如果,序列是顺序的如从小到大,建立的查找二叉树,就会变成一个所有节点只有右孩子的,链表。查找效率会退化成 O(n), 原因就是这棵树不平衡了。判断一个棵树平衡的标准是什么,如何构建和调整一棵树,使他平衡呢。答案就是 平衡二叉树(AVL)
(1)平衡因子
平衡因子:是一个数值,每个节点的平衡因子 = 左子树的高度 - 右子树的高度
(2)平衡二叉的标准是什么?
每个节点的平衡因子的绝对值都不超过1
只是在插入元素,和删除元素时,和二叉排序树不同
参考:https://www.bilibili.com/video/BV1Vy4y1M7cD
avltree.go
package avltree
import (
"fmt"
"sort"
)
type AvlTree struct {
Root *AvlNode
}
type AvlNode struct {
Depth int
Data int
Left, Right, Parent *AvlNode
}
func (a *AvlNode) GetBalancer() int {
if a == nil {
return 0
}
if a.Left.GetDepth()-a.Right.GetDepth() > 0 {
return a.Left.GetDepth() - a.Right.GetDepth()
}
return a.Right.GetDepth() - a.Left.GetDepth()
}
func (a *AvlNode) UpdateDepth() {
if a == nil {
return
}
max := a.Left.GetDepth()
if max < a.Right.GetDepth() {
max = a.Right.GetDepth()
}
a.Depth = max + 1
if a.Parent != nil {
a.Parent.UpdateDepth()
}
}
func (a *AvlNode) GetDepth() int {
if a == nil {
return 0
}
return a.Depth
}
func (a *AvlTree) AddNode(val int) bool {
// 查找二叉树插入
node := AvlNode{Depth: 1, Data: val}
if a.Root == nil {
a.Root = &node
return true
}
current := a.Root
for i := 0; i < 100; i++ {
if current.Data > val {
if current.Left == nil {
current.Left = &node
node.Parent = current
node.UpdateDepth()
a.ReBalance(&node)
return true
} else {
current = current.Left
}
} else {
if current.Right == nil {
current.Right = &node
node.Parent = current
node.UpdateDepth()
a.ReBalance(&node)
return true
} else {
current = current.Right
}
}
}
return false
}
func (a *AvlTree) ReBalance(no *AvlNode) {
// 获取不平衡的元素开始,前三个元素。
current := no
//s := linear.NewStack()
//s.Push(current)
for {
if current.GetBalancer() > 1 {
break
}
current = current.Parent
if current == nil {
return
}
}
var list []*AvlNode
list = append(list, current)
for i := 1; i < 3; i++ {
ele := current.Left
if ele.GetDepth() < current.Right.GetDepth() {
ele = current.Right
}
list = append(list, ele)
current = ele
}
//记录父元素,和父元素分支
if list[0] == a.Root {
a.Root = nil
}
parent := list[0].Parent
isLeft := false
if parent != nil {
isLeft = (parent.Left == list[0])
}
// 擦除三个元素的相互指向
for _, v := range list {
for _, vv := range list {
if v.Left == vv {
v.Left = nil
}
if v.Right == vv {
v.Right = nil
}
v.Parent = nil
}
}
// 排序
sort.SliceStable(list, func(i, j int) bool {
return list[i].Data < list[j].Data
})
//记录多余元素
var appenList []*AvlNode
if list[1].Left != nil {
appenList = append(appenList, list[1].Left)
}
if list[1].Right != nil {
appenList = append(appenList, list[1].Right)
}
//处理父结点
list[1].Parent = parent
if parent != nil {
if isLeft {
parent.Left = list[1]
} else {
parent.Right = list[1]
}
}
//处理左右结点
list[1].Left = list[0]
list[0].Parent = list[1]
list[1].Right = list[2]
list[2].Parent = list[1]
if a.Root == nil {
a.Root = list[1]
}
list[0].UpdateDepth()
list[2].UpdateDepth()
for _, v := range appenList {
a.AddNode(v.Data)
}
}
func (a *AvlTree) DelNode(ele int) bool {
node := a.FindNode(ele)
fmt.Println("find node ", node)
if node == nil {
return false
}
// 1.没有子节点,直接删除,ReBalance父结点
if node.Left == nil && node.Right == nil {
if node.Parent.Left == node {
node.Parent.Left = nil
} else {
node.Parent.Right = nil
}
node.Parent.UpdateDepth()
a.ReBalance(node.Parent)
node.Parent = nil
return true
}
// 2.没有右子树子树,左子树代替自己原来的位置,ReBalance父结点
if node.Left != nil && node.Right == nil {
if node.Parent.Left == node {
node.Parent.Left = node.Left
} else {
node.Parent.Right = node.Left
}
node.Parent.UpdateDepth()
a.ReBalance(node.Parent)
node.Parent = nil
return true
}
// 3.没有左子树,右子树代替自己原来的位置,ReBalance父结点
if node.Left == nil && node.Right != nil {
if node.Parent.Left == node {
node.Parent.Left = node.Right
} else {
node.Parent.Right = node.Right
}
node.Parent.UpdateDepth()
a.ReBalance(node.Parent)
node.Parent = nil
return true
}
// 4.左右子树都有,左子树的最右结点。代替,自己原来位置,原来右结点,变为null,rebalance 最右结点的父结点。
mostRightNode := node.Left
for mostRightNode.Right != nil {
mostRightNode = mostRightNode.Right
}
node.Data = mostRightNode.Data
mostRightNode.Parent.Right = nil
mostRightNode.Parent.UpdateDepth()
a.ReBalance(mostRightNode.Parent)
mostRightNode.Parent = nil
return true
}
func (a *AvlTree) FindNode(ele int) *AvlNode {
current := a.Root
for i := 0; i < 100; i++ {
if current.Data == ele {
return current
}
if current.Data > ele {
if current.Left == nil {
return nil
}
current = current.Left
} else {
if current.Right == nil {
return nil
}
current = current.Right
}
}
return nil
}
func (a *AvlTree) PreOrder() {
a.Root.PreOrder()
}
func (a *AvlNode) PreOrder() {
if a == nil {
return
}
fmt.Printf(" %+v \n", a)
a.Left.PreOrder()
a.Right.PreOrder()
}
avltree_test.go
package avltree
import (
"fmt"
"testing"
)
func TestAvlNode(t *testing.T) {
var tree AvlTree
tree.AddNode(16)
tree.AddNode(3)
tree.AddNode(7)
tree.AddNode(11)
tree.AddNode(9)
tree.AddNode(26)
tree.AddNode(18)
tree.AddNode(14)
tree.AddNode(15)
tree.PreOrder()
aa := tree.FindNode(8)
if aa != nil{
t.Fail()
}
bb := tree.FindNode(11)
if bb == nil {
t.Fail()
}
if tree.Root.GetBalancer() > 1 {
t.Fail()
}
tree.DelNode(26)
fmt.Println("===================================")
tree.PreOrder()
}