AVL树:(3+4)-重构
看完你能亲手画出四种失衡的(3+4)重构并理解其统一本质
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
AVL树:(3+4)-重构
看完你能亲手画出四种失衡的(3+4)重构并理解其统一本质
AVL树失衡的四种情况
上一节我们用 (3+4)-重构统一处理所有失衡。但失衡的形状本身只有四种——都由失衡节点往下走两步的方向决定。
每次左或右,两次拐弯 = 2×2 = 四种组合,对应四种失衡
为什么需要3+4重构
前页说过失衡有四种,对应四种旋转——LL/RR用单旋、LR/RL用双旋。但仔细看,这四套手法其实是同一件事的四个影子。3+4把它们收编成一套统一操作。
3块积木对应3节点,统一卡口对应4子树重接
失衡节点与祖孙三代
上一页我们看到四种失衡形态,但要动手 (3+4) 重构,得先从插入点往上找到「当事人」——失衡的祖父 g、它的孩子 p,以及 p 的孩子 v。
一端加 v 后,支点 g 失去平衡,p 是中间传力的座位
四种情况的节点标识对比
四种失衡横向并排;每型都是 g→p→v 三代,边上 L/R 标出该层走向。
中序遍历序列的规律
上一页我们圈出了 g、p、x 三个节点。重构把它们挪到哪?答案藏在「中序遍历」这条不变的线上。
换队形不换顺序:谁在前谁在后不变,只调站位距离
3+4重构的整体框架
三节点、四棵子树的中序排列与重新连接
三种重构形态的图解
LL/LR/RR/RL四种情况对应的中序排列结果
3+4重构的六步执行流程
六步把失衡子树原地重构成平衡子树,每步都不可省。
平衡因子的修复过程
沿着流程看:记录原高度→3+4重构→验证新高度恰好少一层,bf才算真正修好。
rotateAt()函数的设计思路
六步重构走完后,我们要把这套操作封装成一个函数,调用一次就完成整个修复。不同失衡情况处理逻辑不同,但入口应该统一——这就是 rotateAt() 的设计目标。
接到失衡节点像接到报修单,自己判断故障类型再动手修
rotateAt()的伪代码实现
从 v 沿 parent 找到 p、g,用两层 h 方向判定 LL/LR/RR/RL,再把三代和四棵子树交给 connect34。
两层 h 判断先定 p 相对 g 的方向,再定 v 相对 p 的方向;四个 return 按 LL、LR、RR、RL 传入 3+4 的七个参数。
h方向的判断逻辑图解
沿箭头判断:先看g→p方向定支线,再读p→n方向h决定单/双旋。
连接t1~t4的指针操作
connect34() 的核心:六行指针赋值覆盖所有失衡情况。
前 4 行把四棵子树按中序挂到 a、c 下;后 2 行让 b 接管 a 和 c 成为新子树根——这就是 (3+4) 重构的统一形式。
3+4重构 vs 传统单旋/双旋
四种失衡,传统旋转要写四套逻辑;3+4 一套搞定。边界与复用的差异在哪儿?
- LL/RR/LR/RL 四种情况各自写代码
- 旋转后平衡因子要逐情况修复
- 每个旋转函数单独处理边界
- rotateAt() 一套函数覆盖全部四种
- 中间节点左右子树高决定新平衡因子
- 统一从 t1~t4 接指针,边界一次处理
时间复杂度分析
上一页我们连接了 t1~t4、调整了三个节点——表面看操作不少,实际却只花常数时间。为什么?我们来数清楚到底做了多少事。
只挪4个箱子的位置,箱内物品从不重排
3+4重构核心理解测验
在(3+4)重构中,g是失衡节点,p是g更高的孩子,v是p更高的孩子。若p是g的右孩子、v是p的左孩子,应执行什么旋转?
课后思考
三道开放题,先自己想三分钟,再点开参考答案对照思路。
参考答案失衡高度只受这代子树影响,向上传递即可;重构恢复高度后祖先无需调整。这是AVL'局部修复'的核心保证。
参考答案可在rotateAt()前保存三个节点原高度到临时变量,重连后用真值重算。高度由max(左高,右高)+1推导,不必额外存储。
参考答案够。t1~t4只是'槽位',是否为空指针不影响形态枚举,但需增加空指针判断,避免悬挂访问。