AVL树插入删除算法详解(有图) -- C++语言实现

一:AVL树介绍

AVL树本质上还是一棵二叉搜索树,它的特点是:
1.本身首先是一棵二叉搜索树。
2.带有平衡条件:每个结点的左右子树的高度之差的绝对值(平衡因子)最多为1。在本文中用分别用-1,0,1定义左边树高,等高,右边树高。平衡因子用m_bf表示。
也就是说,AVL树,本质上是带了平衡功能的二叉查找树(二叉排序树,二叉搜索树)。

二:插入算法

由于AVL树具有BST树的特性,所以它的插入算法思路上和BST树基本步骤是相同的,不过在BST树插入算法的基础上增加了由于平衡因子的变动,平衡化平衡因子的步骤,使得整棵树达到平衡因子绝对值不超过1的高度平衡。

在AVL树插入的过程中,为了使树再次平衡,需要作相应的旋转,分为单旋转和双旋转。又细分为左旋转,右旋转,左右旋转,右左旋转。
下面将就其中的主要情况加以说明:
(1)左旋转
左旋转的情况如图所示:
当我们插入元素出现类似的情况时,就需要左旋转来出马了。ptr是传给旋转函数的参数,我们先让ptr走到它的右孩子,用ptr表示旋转后的最上面的节点(有可能为根节点),用sub_left表示旋转后位置在左侧的节点,sub_right表示旋转后位置在右侧的节点(该图还未出现)。下文同此处。当出现上图情况是,我们只需用sub_left替换ptr的左孩子即可,并修改相应的平衡因子。不过有一点很重要,ptr的左孩子并不一定像图中那样为空,所以若要有左孩子,需要先将左孩子赋给sub_left的右孩子。
代码体现如下:
template <typename T>
void avl_tree<T>::rotate_left(node_type *&ptr)
{
	auto sub_left = ptr;      //先指定sub_left
	ptr = ptr->right_child;   //ptr走到它的右孩子

	sub_left->right_child = ptr->left_child;   //将ptr的左孩子覆盖sub_left的右孩子
	ptr->left_child = sub_left;         //旋转
	sub_left->m_bf = ptr->m_bf = 0;    //调整平衡因子
}
(2)右旋转
右旋转和左旋转代码只是镜像关系,就不重述一遍了。
(3)先左旋,后右旋

我们插入时可能碰到上面的情况,可以针对3、7进行左旋转,sub_left替换ptr的左孩子,再对7、16进行右旋转,sub_right替换ptr的右孩子。注意,若ptr有左右孩子,要将ptr的左孩子挂在sub_left的右孩子上,将ptr的右孩子挂在sub_left的左孩子上。
不过双旋转需要注意的是,平衡因子的情况不会像单旋转那么简单了,还可能出现下面的情况:

在这种情况中,2和18结点都是必须的,否则新插入9元素会直接导致3、7、9不平衡,程序直接执行左单旋转,而我们现在要讨论的是双旋转。
图中新增元素9或5,则3、7先左旋转,7、16后右旋转。分情况如下:
1.ptr的平衡因子为0:
  ptr平衡因子为0时,如图2.1,经过双旋转后,参与旋转的节点平衡因子都为0。
2.ptr的平衡因子为1:
  ptr平衡因子为1时,如图2.2,经过旋转后,sub_right的平衡因子为0,sub_left的平衡因子为-1。
3.ptr的平衡因子为-1:
  ptr的平衡因子为-1时,如图2.3,经过旋转后,sub_right的平衡因子为1,sub_left的平衡因子为0。
上述三种情况概括了双旋转平衡因子的变化情况,代码体现如下:
template <typename T>
void
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值