C++AVL树

一,什么是AVL树

当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1,这样的二叉搜索树叫做AVL树。

二, AVL树的性质

1,它的左右子树都是AVL树。
2,任意一个子树的左右子树高度之差(平衡因子)不超过1.
这里的平衡因子是右子树的高度-左子树的高度。

在这里插入图片描述

三,AVL树的模拟实现

3.1 AVL树节点定义

首先我们创建AVL树的结构。
我们定义一个三叉链来创建AVL树,为什么会采用三叉链,因为我们在插入节点的时候,它可能会影响祖先节点的平衡因子,所以可能要沿着祖先节点一直改变平衡因子,所以设计三叉链有助于我们实现。
在这里插入图片描述

3.2 Insert

1,插入一个节点和二叉搜索树的规则一样,大于向右走,小于向左走。相等返回false,找到插入位置,直接插入。
2,插入节点后,会改变节点的祖先节点的平衡因子,所以需要更新平衡因子,更新完后,平衡因子如果不是1,0,-1,就说明该树现在不平衡,则需要调整树的结构,我们用旋转的方法调整。
在这里插入图片描述

3.3 平衡因子更新规则

接下来我们要更新平衡因子,分别由以下几种情况:
1.如果在parent的右边插入,则_bf++,左边插入,_bf–;
在这里插入图片描述

2,如果parent的_bf=0,说明之前parent的_bf一定是1或者-1,新插入的节点一定插入在了parent节点子树的矮的一边,此时达到平衡,不需要向上更新平衡因子。
在这里插入图片描述

3,如果parent的_bf=1或者-1,说明之前parent的_bf一定是0,插入节点后更新成了1或者-1,此时以parent为子树的高度增加,会影响祖先节点的_bf,所以要向上更新,直到更新到根节点结束。
在这里插入图片描述
4,如果parent的_bf=2或者-2,说明parent插入前的平衡因子是1 或者 -1,打破平衡,此时不符合AVL树的性质,需要对其进行旋转处理。
5,更新后,parent->_bf>2 or <-2的值,不可能,如果存在,说明插入前就不是AVL树,需要检查之前的操作。
在这里插入图片描述

3.4 AVL的旋转

如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,
使之平衡化。根据节点插入位置的不同,AVL树的旋转分为四种:
1,新节点插入较高右子树的右侧—右右:左单旋。
抽象图:
在这里插入图片描述

上面这个图是一个抽象图,a,b,c分别是高度为h的AVL子树,在c中插入新节点后,导致右边子树高度变高,导致祖先节点的平衡因子发生变化,打破平衡,此时需要进行旋转.
怎么旋转:因为parent的右孩子cur一定大于parent,cur的左孩子一定大于parent并且小于cur,所以我们将parent做cur的左孩子,cur的左孩子做parent的右孩子,达到平衡。
下面我们画几个具象图来更好的观察。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为了完成旋转,我们首先给上述几个要改变的位置起上名字如上图,首先,我们先处理subR节点,subR->_right=parent; parent->parent=subR;接着,我们处理subRL节点,因为subRL可能为空,所以我们加上判断,然后将parent->_right=subRL; subRL->_parent=parent; 最后,我们不要忘了要处理最后旋转完成的根节点的处理,这里有两种情况,一种是旋转之后的子树的根节点就是整棵树的根节点,那么我们直接将_root=subR;然后将subR->_parent置空,另一种情况是旋转之后的子树是整棵树的一个子树,那么我们还需要添加一个指针ppNode来保存最开始parent的父节点,接着使subR->parent=ppNode; 最后还需要判断subR到底是ppNode的左孩子还是右孩子,然后再进行处理。
最后更新平衡因子,平衡之后都是0;
在这里插入图片描述

2, 新节点插入较高左子树的左侧—左左:右单旋。

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

3,新节点插入较高左子树的右侧—左右:先左单旋再右单旋。

在这里插入图片描述
这里分三种情况:
1,上图不好演示过程,需要再往下画一层。
在这里插入图片描述
在b位置新增节点,此时b的高度为h改变了祖先节点的平衡因子,此时90的平衡因子为-2,打破平衡,需要旋转,我们先以30为轴点进行左旋,再以90为轴进行右旋,旋转完之后,达到平衡此时我们需要改变平衡因子,因为在旋转的过程中,a,b,c,d本身的高度没有改变,改变的只有Parent,subL,subLR,所以我们先记录旋转前60的平衡因子,如果是-1,那么最后旋转之后,parent_bf
=1,sub_bf=0,subLR_bf=0;
2,在c上插入新节点。
在这里插入图片描述
在c位置新增节点,此时c的高度为h改变了祖先节点的平衡因子,此时90的平衡因子为-2,打破平衡,需要旋转,我们先以30为轴点进行左旋,再以90为轴进行右旋,旋转完之后,达到平衡此时我们需要改变平衡因子,因为在旋转的过程中,a,b,c,d本身的高度没有改变,改变的只有Parent,subL,subLR,所以我们先记录旋转前60的平衡因子,如果是1,那么最后旋转之后,parent_bf
=0,sub_bf=-1,subLR_bf=0;

3,当h=0时,那么60就是新增节点,我们先以30为轴进行左旋,再以90为轴进行右旋。在这里插入图片描述
此时parent_bf=0=sub_bf=subLR_bf=0;
在这里插入图片描述

4,新节点插入较高右子树的左侧:先右单旋再左单旋。
和左右双旋类似。
在这里插入图片描述

综上,不平衡时,根据parent和cur的平衡因子,可以判断出要用哪种旋转。
在这里插入图片描述

四, 验证AVL树

我们用什么方法来验证是否为AVL树,
1, 验证其为二叉搜索树,如果中序遍历可得到一个有序的序列,就说明为二叉搜索树。
2. 验证其为平衡树我们可以通过判断每颗子树的abs(平衡因子)是否小于2,如果小于2就是平衡,大于2就不平衡。
在这里插入图片描述

在这里插入图片描述
删除
由于删除很复杂,这里不再赘述。

五,AVL树的性能

AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这
样可以保证查询时高效的时间复杂度,即log2 (N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值