目录
AVL树的概念
AVL树介绍
平衡因子
AVL树的插入
平衡因子的更新
【1】平衡因子为0
【2】平衡因子为1/-1
【3】平衡因子为2/-2
选择的处理
旋转的原则
右单旋
具体的三种情况:
编辑 所有情况的概念图:
对于父亲指针的处理 :
左单旋
具体的三种情况:
左右双旋
具体情况例子:
右左双旋
代码示例:
AVL树的概念
- AVL数是一棵具有二叉搜索树性质,并且左右子树的高度差不超过1的树
- AVL树还可以是一棵空树
AVL树的发明者:G.M.Adelson-Velsky和E.M.Landis是两个前苏联的科学家
AVL树介绍
- AVL树遵循二叉搜索树的规则:左边小于根节点,右边大于根节点
- 本次AVL树的实现借助平衡因子的概念
平衡因子
- 每个节点都有一个平衡因子,该平衡因子等于右子树的高度减去左子树的高度
- 可以说任何节点的平衡因子可能是0/1/-1
- 平衡因子并不是AVL树的必须品,但它可以作为一个观察风向标,使我们更加方便观察和控制AVL树的平衡
注意: 如果平衡因子大于等于2,说明该树已经不平衡不再是一棵AVL树,需要调节平衡!
AVL树是高度平衡的二叉搜索树这个高度为什么设置为1,而不是0呢,因为存在某些特殊情况,高度无法达到0
AVL树整体结点数量和分布和完全二叉树类似,⾼度可以控制在logN,那么增删查改的效率也可 以控制在O(logN),相比二叉搜索树有了本质的提升。
AVL树的插入
- 按照二叉搜索树的规则插入
- 根据新增的节点更新平衡因子
平衡因子的更新
更新规则:
- 平衡因⼦=右子树⾼度-左子树⾼度
- 只有⼦树高度变化才会影响当前结点平衡因⼦
- 插⼊结点,会增加⾼度,所以新增结点在parent的右⼦树,parent的平衡因⼦++,新增结点在 parent的左子树,parent平衡因⼦--
- parent所在子树的⾼度是否变化决定了是否会继续往上更新
更新停止条件:
【1】平衡因子为0
更新后parent的平衡因⼦等于0,更新中parent的平衡因⼦变化为-1->0或者1->0,说明更新前parent⼦树⼀边⾼⼀边低,新增的结点插⼊在低的那边,插⼊后parent所在的⼦树⾼度不变,不会影响parent的⽗亲结点的平衡因⼦,更新结束
【2】平衡因子为1/-1
更新后parent的平衡因⼦等于1或-1,更新前更新中parent的平衡因⼦变化为0->1或者0->-1,说明更新前parent⼦树两边⼀样⾼,新增的插⼊结点后,parent所在的⼦树⼀边⾼⼀边低,parent所在的⼦树符合平衡要求,但是⾼度增加了1,会影响arent的⽗亲结点的平衡因⼦,所以要继续向上更新
- 更新到中间结点,3为根的⼦树⾼度不变,不会影响上⼀层,更新结束
- 最坏更新到根停⽌
【3】平衡因子为2/-2
更新后parent的平衡因⼦等于2或-2,更新前更新中parent的平衡因⼦变化为1->2或者-1->-2,说明更新前parent⼦树⼀边⾼⼀边低,新增的插⼊结点在⾼的那边,parent所在的⼦树⾼的那边更⾼了,破坏了平衡,parent所在的⼦树不符合平衡要求,需要旋转处理,旋转的⽬标有两个:1、把parent⼦树旋转平衡。2、降低parent⼦树的⾼度,恢复到插⼊结点以前的⾼度。所以旋转后也不需要继续往上更新,插⼊结束
选择的处理
旋转的原则
- 保持搜索树的规则
- 让旋转的树从不平衡变平衡,其次降低旋转树的⾼度
- 旋转总共分为四种,左单旋/右单旋/左右双旋/右左双旋
右单旋
具体的三种情况:
所有情况的概念图:
触发右单旋的条件:parent->_bf == -2 && cur->_bf == -1
右单旋的具体操作:5<b子树的数据<10,进行旋转时,我们将b子树作为10的左子树,然后10作为5的右子树,同样我们也需要更改他们的_parent节点,最后5节点和10节点的平衡因子为0
对于父亲指针的处理 :
当我们完成上述的连接之后我们需要考虑subL的父亲节点是什么
- 1. 原本的parent是_root,那么新的subL将成为_root节点,其_parent->nullptr
- 2. 原本的parent是其他节点,那么subL的父亲节点需要判断原本的parent在他的_parent的左子树还是右子树,指向subL
左单旋
具体的三种情况:
其他情况处理与右单旋相似
左右双旋
具体情况例子:
以上如果我们只通过一个单旋操作是无法实现条件平衡的
- 先对subL进行一个左单旋,再对parent进行一个右单旋
- 根据图像观察我们可以发现,最后的步骤可以简化为将subLR的左子树给subL的右,bf++;subLR的右子树给parent的左,bf--; 我们只需要记录subLR的bf即可,如果subLR的bf为0,那么所有参与节点的bf最后都为0;如果subLR的bf为1,那么subL->_bf=-1;如果subLR的bf为-1,那么parent->_bf=1;
右左双旋
- 先对subR进行一个右单旋,再对parent进行一个左单旋
- 根据图像观察我们可以发现,最后的步骤可以简化为将subRL的右子树给subR的左,bf--;subRL的左子树给parent的右,bf++; 我们只需要记录subRL的bf即可,如果subRL的bf为0,那么所有参与节点的bf最后都为0;如果subRL的bf为1,那么parent->_bf=-1;如果subRL的bf为-1,那么subR->_bf=1;
代码示例:
C++_Test_AVLTree_2024_10_29 · 阳区欠/CPlusPlus学习仓库 - 码云 - 开源中国