AVL树及其实现(C++)

一、AVL树简单介绍

在前面二叉搜索树中,我们可以看出它的查找销率非常高,最优可到达O(Log2(N)),但是当数据越接近有序的时候二叉搜索树将退化成一个链表,查找效率就能变成了O(N),因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis(AVL的由来)发明了AVL树:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
性质1:左右子树都是AVL树
性质2:左右子树的高度之差(平衡因子)的绝对值不能超过1。
这样,AVL树的搜索时间复杂度就一定在O(Log2(N))。

在这里插入图片描述
二、插入

1、先按照二插搜索树的方法找到插入的位置并插入
2、插入完后判断插入节点的是它父节点的左孩子还是右孩子:
左孩子—>给父节点的平衡因子-1
右孩子—>给父节点的平衡因子+1
3、父节点平衡因子的判断:
(1) 若父节点平衡因子 = 1或 = -1,继续向上判断,并且每次修改父节点的平衡因子,是父节点的左孩子就 -1,右孩子就 +1,直到找到根或者进入(2)、(3)退出
在这里插入图片描述
(2) 若父节点平衡因子的绝对值 > 1,开始调整(具体操作在下面旋转中解释)
在这里插入图片描述
(3) 若父节点平衡因子=0,因为其平衡因子虽然改变,但树高没有发生变化,不会影响父节点的平衡因子,不用调整,直接退出即可在这里插入图片描述

三、旋转

细分可分为6种情况,但是其他的情况都是建立的左右旋的基础之上,而且左右旋还是镜像关系,所以下面只讨论两种情况,左旋和右旋左旋(包括其中的两种情况)

在这里插入图片描述
1、左旋

在这里插入图片描述
①将pre的父节点右节点确立父子关系
②将cur的右孩子过继给pre,cur的右孩子若存在就认pre做爸爸,不存在那就让pre的左孩子指向空即可
③最后pre认cur做父亲,cur认pre做孩子
④旋转完毕之后,cur的左孩子成了pre的右孩子,高度和pre的左孩子相同,所以pre的平衡因子置为0,pre的高度为H-1那么cur的左孩子高度就是H-1+1(pre) = H = 右孩子,平衡因子=0
右旋和左旋是镜像关系,所以将所有的左孩子和右孩子交换就是右旋

2、右旋左旋

在这里插入图片描述
最左边的树插入之前还是平衡的,当在其L节点的任意孩子插入节点之后就会导致他的爷爷节点平衡因子 = 2,开始调整,分为两种情况:
(1)在L节点的左孩子插入了节点导致不平衡:
①先对C和L节点进行右旋,旋成右右的情况。此时L被旋上去,C被旋下来,L的右孩子(没有插入节点的孩子)被挂到C节点的左孩子上,导致C节点平衡因子 = 1。
②在对pre和L进行一次左旋,L的左孩子(插入节点的孩子)被挂到了P的右孩子上,导致P的平衡因子 = 0。
③两次旋转完毕后,P和C成了的L的左右孩子,P的深度为H,C的深度为H,所以L的平衡因子 = 0。
(2)在L节点的右孩子插入了节点导致不平衡:
①先对C和L节点进行右旋,旋成右右的情况。此时L被旋上去,C被旋下来,L的右孩子(插入节点的孩子)被挂到C节点的左孩子上,导致C节点平衡因子 = 0。
②在对pre和L进行一次左旋,L的左孩子(没有插入节点的孩子)被挂到了P的右孩子上,导致P的平衡因子 = -1。
③两次旋转完毕后,P和C成了的L的左右孩子,P的深度为H,C的深度为H,所以L的平衡因子 = 0。

五、代码实现 :GitHub(相当详细的注释,就怕自己哪天忘了,翻出来看看)

发布了77 篇原创文章 · 获赞 16 · 访问量 6510

猜你喜欢

转载自blog.csdn.net/weixin_43886592/article/details/103528955