GO数据结构——AVL树

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 删除

删除元素有四种情况:

  1. 删除的节点是叶子节点,没有儿子,直接删除后看离它最近的父亲节点是否失衡,做调整操作。

  2. 删除的节点下有两个子树,找出目标节点的右子树的最小值赋给目标节点,后,递归删除赋值的结点。

  3. 删除的节点只有左子树,可以知道左子树其实就只有一个节点,被删除节点本身(假设左子树多于2个节点,那么高度差就等于2了,不符合AVL树定义),将左节点替换被删除的节点,最后删除这个左节点,变成情况1。

  4. 删除的节点只有右子树,可以知道右子树其实就只有一个节点,被删除节点本身(假设右子树多于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  //返回新的根节点
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

音光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值