1. 简介
AVL树是一种严格自平衡的二叉查找树。
定义:
1.二叉查找树
2.任意一个节点的左右子树的最大高度差为1
2. AVL树基本结构
2.1 AVL树基础函数
type AVLNode struct {
Data interface{}
Right *AVLNode
Left *AVLNode
Height int
}
//比大小
func compare(a,b interface{})int{
var newA,newB int
var ok bool
if newA,ok=a.(int);!ok{
return -2
}
if newB,ok=b.(int);!ok{
return -2
}
if newA >newB{
return 1
}else if newA <newB{
return -1
}else{
return 0
}
}
//新建结点
func NewNode(data interface{})*AVLNode{
node:=new(AVLNode)//新建节点,初始化
node.Data=data
node.Left=nil
node.Right=nil
node.Height=1
return node
}
//新建AVL Tree
func NewAVLTree(data interface{})(*AVLnode,error){
if data==nil{
return nil,errors.New("不能为空")
}
return NewNode(data),nil
}
//获取
func (avlnode *AVLNode) GetData()interface{}{
return avlnode.Data
}
func (avlnode *AVLNode) GetRight()*AVLNode{
return avlnode.Right
}
func (avlnode *AVLNode) GetLeft()*AVLNode{
return avlnode.Left
}
func (avlnode *AVLNode) GetHeight()int{
return avlnode.Height
}
//设置data
func (avlnode *AVLNode) SetData(data interface{}){
avlnode.Data=data
}
//最大
func (avlnode *AVLNode) GetMax()*AVLNode{
var finded *AVLNode
if avlnode.Right!=nil{
finded=avlnode.Right.GetMax()
}else{
finded=avlnode
}
return finded
}
//最小
func (avlnode *AVLNode) GetMin()*AVLNode{
var finded *AVLNode
if avlnode.Left!=nil{
finded=avlnode.Left.GetMin()
}else{
finded=avlnode
}
return finded
}
3. AVL树基本操作
3.1 左子树插左儿子:单右旋
插入红色结点,使root左子树高度为2,右子树高度为0,失衡。需要重新平衡,重新平衡,围绕Pivot右旋,黄色结点旋转至右边,root更新为绿色结点,更新右子树关系。
//右旋
func (avlnode *AVLNode) RightRotate()*AVLNode{ //传入的黄色结点为avlnode
headnode:=avlnode.Left //新建结点保存avlnode.Left,并将绿色结点赋给它headnode即为绿色结点
avlnode.Left=headnode.Right //把绿色右子树赋给黄色左边(更改黄色结点左子树指向关系)
headnode.Right=avlnode //黄色结点赋给绿色结点右边(更改绿色结点右子树指向关系)
avlnode.Height=Max(avlnode.Right.Height,avlnode.Left.Height)+1 //更新黄色结点高度
headnode.Height=Max(headnode.Right.Height,headnode.Left.Height)+1 //更新绿色结点高度
return headnode //返回右旋后的根节点
}
3.2 右子树插右儿子:单左旋
插入蓝色结点,导致root左右子树高度差大于1,需要更改绿色和黄色结点指向关系,root更新为黄色结点,更新黄色结点左子树指向关系,指向右子树。
//左旋
func (avlnode *AVLNode) LeftRotate()*AVLNode{ //传入的绿色结点为avlnode
headnode:=avlnode.Right //新建结点保存avlnode.Right,并将黄色结点赋给它,headnode即为黄色结点
avlnode.Right=headnode.Left //黄色左子树赋给绿色右边(更改绿色结点右子树指向关系)
headnode.Left=avlnode //绿色结点赋给黄色结点左边(更改黄色结点左子树指向关系)
avlnode.Height=Max(avlnode.Right.Height,avlnode.Left.Height)+1 //更新绿色结点高度
headnode.Height=Max(headnode.Right.Height,headnode.Left.Height)+1 //更新黄色结点高度
return headnode //返回左旋后的根节点
}
3.3 左子树插右儿子:先左后右
//先左再右
func (avlnode *AVLNode) LeftThenRightRotate()*AVLNode{ //传入的avlnode为黄色结点
sonhead:=avlnode.Left.LeftRotate() //对绿色结点进行左旋 返回的sonhead为红色结点
avlnode.Left=sonhead //更改黄色结点左子树指向关系,红色结点为黄色结点左子树
return avlnode.RightRotate() //对黄色结点进行右旋,返回红色结点
}
3.4 右子树插左儿子:先右后左
//先右再左
func (avlnode *AVLNode) RightThenLeftRotate()*AVLNode{ //传入的avlnode为绿色结点
sonhead:=avlnode.Right.RightRotate() //对黄色结点进行右旋,返回的sonhead为红色结点
avlnode.Right=sonhead //更改绿色结点右子树指向关系,绿色结点右子树为红色结点
return avlnode.LeftRotate() //对绿色结点进行左旋,返回红色结点
}
3.5 自动平衡
//自动平衡
func (avlnode *AVLNode) adjust()*AVLNode{
if avlnode.Left.GetHeight()-avlnode.Right.GetHeight()==2{ //左子树高度比右子树高度大2
if avlnode.Left.Left.GetHeight()>avlnode.Left.Right.GetHeight(){ //情况1 左子树的左孩子高度>右孩子高度
avlnode=avlnode.RightRotate()
}else { //情况2 左子树的左孩子高度小于等于右孩子高度
avlnode=avlnode.LeftThenRightRotate()
}
} else if avlnode.Right.GetHeight()-avlnode.Left.GetHeight()==2 { //右子树高度比左子树高度大2
if avlnode.Right.Right.GetHeight()>avlnode.Right.Left.GetHeight(){ //情况3 右子树的右孩子高度>左孩子
avlnode=avlnode.LeftRotate()
}else { //情况4 右子树的右孩子高度小于等于左孩子高度
avlnode=avlnode.RightThenLeftRotate()
}
}
return avlnode //返回自动平衡后的根节点
}
4. AVL树功能函数实现
4.1 插入
func (avlnode *AVLNode) Insert(data interface{})*AVLNode{
if avlnode==nil{ //先检查根节点是否为空 后续循环的avlnode则为上一层递归返回的 newnode进行自动平衡后的返回的结点
newnode:=&AVLNode{data,nil,nil,1}
return newnode //根节点不存在则重新创建 存在则是找到目标位置后 创建的新插入节点并返回进 行自动平衡
}
switch compare(data,avlnode.Data) { //递归比较目标插入节点与当前节点的值
case -1:
avlnode.Left=avlnode.Left.Insert(data)
avlnode.adjust() //创建newnode后 进行自动平衡
case 1:
avlnode.Right=avlnode.Right.Insert(data)
avlnode.adjust()
case 0:
fmt.Println("data is exist")
}
return avlnode //返回新的根节点
}
//这里的递归 从下至上 从插入的地方的newnode开始 返回newnode给上一级进行自动平衡
//对返回的newnode(avlnode)进行自动平衡 并把自动平衡后的结点返回给再上一级 直到平衡出新的根节点
4.2 查找
func (avlnode *AVLNode) Find(data interface{})*AVLNode{ //递归思维和插入功能一样
var finded *AVLNode=nil
switch compare(data,avlnode.Data) {
case 1:
finded=avlnode.Right.Find(data)
case -1:
finded=avlnode.Left.Find(data)
case 0:
return avlnode
}
return finded
}
4.3 删除
删除元素有四种情况:
-
删除的节点是叶子节点,没有儿子,直接删除后看离它最近的父亲节点是否失衡,做调整操作。
-
删除的节点下有两个子树,找出目标节点的右子树的最小值赋给目标节点,后,递归删除赋值的结点。
-
删除的节点只有左子树,可以知道左子树其实就只有一个节点,被删除节点本身(假设左子树多于2个节点,那么高度差就等于2了,不符合AVL树定义),将左节点替换被删除的节点,最后删除这个左节点,变成情况1。
-
删除的节点只有右子树,可以知道右子树其实就只有一个节点,被删除节点本身(假设右子树多于2个节点,那么高度差就等于2了,不符合AVL树定义),将右节点替换被删除的节点,最后删除这个右节点,变成情况1。
func (avlnode *AVLNode) Delete(data interface{})*AVLNode{ //递归思维和插入功能一样
if avlnode ==nil{
return nil
}
switch compare(data,avlnode.Data) { //对比目标节点与当前节点的值的大小 递归寻找目标节点
case -1:
avlnode.Left=avlnode.Left.Delete(data)
case 1:
avlnode.Right=avlnode.Right.Delete(data)
case 0:
if avlnode.Left!=nil&&avlnode.Right!=nil{ //目标节点的左右节点都不为空
avlnode.Data=avlnode.Right.GetMin().Data //目标节点的右子树的最小值赋给目标节点
avlnode.Right=avlnode.Right.Delete(avlnode.Data) //递归删除上一步赋值的结点
}else if avlnode.Left!=nil {
avlnode=avlnode.Left //情况3 目标节点只有左节点 左节点直接替换目标节点
}else {
avlnode=avlnode.Right //情况4 目标节点只有右节点 右节点直接替换目标节点
}
}
if avlnode!=nil{
avlnode.Height=Max(avlnode.Right.GetHeight(),avlnode.Left.GetHeight())+1 //更新高度
avlnode.adjust() //自动平衡
}
return avlnode //返回新的根节点
}