(c)平衡与等价

官方信息技术老师·29 页·深入(追求细节与边界)·0 次浏览·1 天前
BST平衡树旋转等价变换

平衡与等价

看完你能亲手推导平衡条件并解释等价变换的边界

按 空格/→ 演示下一步

1 / 29 页

全部页面点击任意一页,跳回舞台从这页播放

BST平衡树旋转等价变换

平衡与等价

看完你能亲手推导平衡条件并解释等价变换的边界

1第 1 页 · 平衡与等价

BST的基本查找效率

上一节我们看到,平衡让 BST 退化为「逐层折半」。顺着这条线索,本节把它说透:为什么平衡的树每次比较都能砍掉一半候选,从而达到 O(log n)?

代价等于树高
查找只沿一条根到叶的路径走,比较次数 = 树高 h
高度约等于 log n
完美平衡时每层结点数翻倍,n 个结点的树高 ≈ log₂ n
等价于二分查找
每比较一次砍掉一半候选,与有序数组的二分同构
猜数字游戏对应 →平衡 BST 查找

你说一个数,我答大/小,每次把候选范围砍半

T(n)=O(h)=O(log2n)T(n) = O(h) = O(\log_2 n)
2第 2 页 · BST的基本查找效率

有序插入:退化成链表

从根 1 出发,顺右侧箭头依次读 2→3→4→5;所有左箭头都指向空,结构等同于单链表。

图解渲染中…
aL左孩子为空:每个新值都更大,无人落到左侧d2最深的 5:树高 = 节点数 n
3第 3 页 · 有序插入:退化成链表

退化的代价:查找变成O(n)

上一页已经看到,按有序序列插入,BST 会一路向右退化成一条单链。这条「长得像链表」的树,搜索代价到底是多少?和真正的链表拉出来直接比一比。

树高变 n
退化成链表后深度等于 n,再没有 log₂n 那种理想砍半
查找退化为 O(n)
每层只排除 1 个候选,最坏需要 n 次比较
与链表同档
单链表顺序查找也是 O(n),BST 完全没占便宜
结构红利归零
左右指针开销还在,但时间上的加速全丢了
查字典翻中间对应 →退化后逐页翻

BST 像查字典每次砍一半,退化后只能从首页一页页翻

T平衡=O(log2n),  T退化=O(n)T_{\text{平衡}} = O(\log_2 n),\; T_{\text{退化}} = O(n)
4第 4 页 · 退化的代价:查找变成O(n)

为什么关心平均情况

上一页说最坏能退化成 O(n),但那是刻意按顺序插入的结果。真实工程里数据往往是乱的,罕有人专门构造最坏情况。我们真正关心的是「典型情况下到底有多快」。

最坏情况罕见
有序插入是刻意为之,正常数据几乎遇不到
平均假设
假设输入均匀随机,看期望复杂度
平均查找代价
约 1.39 log₂n,常数小但仍是 O(log n)
反映工程实际
用户关心典型表现,不关心能否刻意构造极坏
排队买早餐对应 →BST查找效率

「可能排最久」是上界,「通常要多久」才是日常体验

E[T]1.386log2nE[T] \approx 1.386 \log_2 n
5第 5 页 · 为什么关心平均情况

随机插入的高度期望

沿推导链读:随机顺序→根均分→子树减半→递推求解。

图解渲染中…
d1约指期望值,实际左右子树规模会有波动f1期望高度的递推式,根占1层加子树期望高度g1递推求解得到对数深度,关键在于每层规模减半
6第 6 页 · 随机插入的高度期望

最好vs平均vs最坏

三种插入顺序,决定 BST 是高效还是崩溃——它们之间差的不只是速度,而是量级。

最好/平均情况
  • 树高约 log₂n,层数极少
  • 查找、插入、删除都是 O(log n)
  • 平衡插入或随机插入时出现
最坏情况
  • 树高退化为 n,变成链表形态
  • 查找、插入、删除都变成 O(n)
  • 有序或逆序插入时触发
平均期望才是真实预期——插入不过于有序时,期望高度为 O(log n);一旦有序输入,树高就退化为 O(n),需自平衡 BST 兜底。
7第 7 页 · 最好vs平均vs最坏

完全二叉树的形态

前面看到随机插入能让高度趋近期望值,但「运气」不可控。有没有一种树的形态是结构上就保证平衡的?完全二叉树就是其中最经典的一种。

每层必满
除最后一层外,每一层的节点数都达到最大值
最底左对齐
最后一层节点从左往右连续排列,中间不能跳着留空
高度约 log n
节点数翻一倍,高度只增加一层,对数级增长
电影院前排坐满、最后排从左坐起对应 →完全二叉树

前排满座 = 中间层满节点;最后排从左坐起 = 最后一层左对齐连续填

h=log2nh = \lfloor \log_2 n \rfloor
8第 8 页 · 完全二叉树的形态

完全二叉树的性质

从完全二叉树形态看高度h与节点数n的精确数量关系

图解渲染中…
c2第k层节点数=2^(k-1): 1, 2, 4, 8...d1高度h时节点最少2^h个(最后一层仅1节点)d2节点最多2^(h+1)-1个(恰好满二叉树)e1由n反推h: h = floor(log2 n)
9第 9 页 · 完全二叉树的性质

平衡因子:理想值为0

完全二叉树是教科书里最理想的形态,但真实插入顺序千变万化,没有两棵树长得一样。我们需要一个数字来量化「这棵树离理想有多远」——左右子树的高度差,就是平衡因子。

定义
左子树高度减去右子树高度
理想值 0
左右等高,最接近完全二叉树形态
AVL 允许范围
限定在 -1、0、1 三档,超出就要调整
失衡信号
绝对值大于 1,意味着子树已明显倾斜
天平两端的砝码差对应 →平衡因子

砝码偏重对应子树偏高,差为零就水平

bf(node)=height(left)height(right)bf(node) = height(left) - height(right)
10第 10 页 · 平衡因子:理想值为0

理想平衡的查找效率

高度h对应O(log₂(n+1))复杂度

理想平衡的查找效率
高度h对应O(log₂(n+1))复杂度
11第 11 页 · 理想平衡的查找效率

理想平衡的维护代价

上页说理想平衡带来 O(log n) 的查找效率。但插入一个新节点后,理想平衡往往就被打破。修复需要多大代价?这就是这页要回答的问题。

完美平衡很脆弱
一次插入就可能让多个祖先节点失衡
恢复需全局重构
失衡点之上的子树全部重建,时间 O(n)
维护代价不可接受
单次插入从 O(log n) 退化到 O(n)
实际选择近似平衡
AVL 只要 |平衡因子|≤1,红黑树约束更松
摞完全等高的碗对应 →完美平衡的BST

完美等高要求每加一个碗都重整整摞;允许小幅偏差只微调顶部

Tinsertperfect=O(n)vs.TinsertAVL=O(logn)T_{\text{insert}}^{\text{perfect}} = O(n) \quad\text{vs.}\quad T_{\text{insert}}^{\text{AVL}} = O(\log n)
12第 12 页 · 理想平衡的维护代价

适度平衡的核心思想

上一页我们看到,追求完美平衡的维护代价不小——每次插入都可能引发大规模调整。能不能允许一点点偏差,换来维护上的轻松?

允许偏差
放弃严格平衡,接受树高在小范围内波动
维护简化
放宽标准后,多数插入删除不再触发旋转
查询略损
树高可能比最优稍高,查找路径略长
收益为正
查询的小损失远小于维护的大节省
整理衣柜差不多整齐对应 →适度平衡

衣柜看着整齐就好,不必每件间距完全一样

13第 13 页 · 适度平衡的核心思想

AVL树的平衡标准

从任一节点算BF,按|BF|大小分流,标出合法边界。

图解渲染中…
a1树中被检查的任一节点c1BF = 左高 - 右高d1核心判定:看|BF|与1的关系f2失衡时必须通过旋转修复
14第 14 页 · AVL树的平衡标准

红黑树的平衡标准

自上而下读:5条规则 → 路径约束 → 高度上界 → 维护代价的因果链。

图解渲染中…
a3黑高:任一节点到所有叶子路径上的黑色节点数相同a6全黑路径最短,红黑交替路径最长,长度不超过2倍
15第 15 页 · 红黑树的平衡标准

严格平衡vs宽松平衡

AVL要求每个节点左右严格平衡,红黑树放宽到路径长度比——两种思路直接决定增删查的取舍。

AVL严格平衡
  • 标准:左右子树高度差≤1
  • 查找:更贴近完全二叉树
  • 代价:增删常需多次旋转
红黑树宽松平衡
  • 标准:最长路径≤2倍最短
  • 查找:O(log n),略逊AVL
  • 代价:增删旋转少,≤3次
查询远多于增删选AVL;读写均衡或增删频繁选红黑树——宽松换来维护效率。
16第 16 页 · 严格平衡vs宽松平衡

什么是「等价」的BST

一组数字按不同顺序插入,会得到形态各异的BST——有的高瘦像竹竿,有的矮胖像蘑菇。它们是否等价?判别只看一件事,和形态毫无关系。

等价定义
两棵BST持有相同的元素(多重集),即为等价
与形态无关
高度、形状、平衡与否都不参与等价判定
集合视角
把BST看作保存元素的有序多重集,结构只是存取方式
一副扑克牌对应 →等价BST

花色数字全相同就是同一副牌,洗牌顺序不同不影响这副牌本身

T1T2    x:count(x,T1)=count(x,T2)T_1 \equiv T_2 \iff \forall x:\,\text{count}(x, T_1) = \text{count}(x, T_2)
17第 17 页 · 什么是「等价」的BST

等价BST的例子

同一组数据的不同树形态

等价BST的例子
同一组数据的不同树形态
18第 18 页 · 等价BST的例子

为什么关注等价性

上页我们看到,多棵形态各异的BST可以拥有相同的中序序列——对外部世界'长得一样'。这并非偶然,而是平衡算法能存在的根基——等价性给了我们'不改数据、只调结构'的自由。

等价的BST
中序序列相同,对外操作表现完全一致
形态不唯一
同一组数据,能拼出多种不同形状的BST
等价变换
旋转、重构只改结构,不动序列
借变换求平衡
牺牲一点维护成本,换来高度显著下降
书架上书按字母排好对应 →等价的BST

字母顺序=中序序列,书在几层架=树形,换层架不破坏字母顺序

19第 19 页 · 为什么关注等价性

旋转的本质

前面看到,等价的BST能长成截然不同的形态——有的瘦高像链条,有的矮胖较平衡。从一种形态变成另一种,靠的不是整体重建,而是一种局部变形——这就是「旋转」。

局部操作
只动支点和它的子树,远处节点完全不受影响
父子易位
支点和某个子女交换位置,子树随之重挂
中序不变
旋转前后中序遍历结果相同,BST有序性不丢失
等价桥梁
旋转是把一种等价BST变成另一种的基本动作
转盘餐桌对应 →树的旋转

菜品绕中心转动,相对顺序不变;节点绕支点重排,中序不变

20第 20 页 · 旋转的本质

右旋的步骤分解

右旋是BST维持平衡的基本动作,把X绕左子L顺时针转一圈,整个过程分四步,缺一不可。

1
锁定支点
确定要旋转的节点X和左子L,L将成为新的支点
2
L顶替上位
L占据X原来的位置,成为这棵子树的新根
3
X下挂为右子
X变成L的右孩子,原本的父子关系反转
4
移交原右子树
L原来的右子树LR挂到X的左侧,保住BST的序
21第 21 页 · 右旋的步骤分解

左旋的步骤分解

一次左旋让过深的右子树变浅,支点是失衡节点的右孩子

1
识别失衡节点与支点
找出父节点X和它的右孩子R,准备旋转
2
R升为新根
R替换X的位置接管子树,其余父链不变
3
X降为R左孩子
X下沉,成为R的新左子节点
4
RL过继给X
R原来的左孩子RL转挂到X的右指针下
22第 22 页 · 左旋的步骤分解

旋转保持等价性

原树经右旋变新树,节点位置改变但中序遍历相同 → 两棵BST等价

图解渲染中…
OP右旋操作:左子2提升为新根,原根3降为2的右子EQ等价判据:只看中序遍历序列,与树形态无关
23第 23 页 · 旋转保持等价性

旋转改变树高

沿流程看一棵左斜树如何通过右旋把高度压低一层。

图解渲染中…
a1原始链 3→2→1, 高度=3, 已严重左偏a4旋转后 2升为根, 1和3分居两侧, 高度=2
24第 24 页 · 旋转改变树高

等价变换的应用场景

两种自平衡树共用BST等价变换,但触发条件和策略选择截然不同

图解渲染中…
c3LL/RR/LR/RL四种旋转,按失衡方向选d2叔叔节点颜色决定走改色还是旋转分支d3改色不改形,O(1)成本最低
25第 25 页 · 等价变换的应用场景

平衡与等价的统一视角

前面看到,插入顺序不同可能得到形状不同、甚至退化的 BST;但只要中序遍历相同,它们保存的键值序列就相同。接下来把这两件事放在一起看。

等价类
中序遍历相同、键值序列相同的 BST,归为同一等价类
类内选形
平衡不是改变数据,而是在同一等价类里选择更低、更均衡的树形
旋转保序
旋转只调整局部父子关系,中序遍历和键值顺序保持不变
统一目标
通过控制树高,降低查找以及后续插入、删除的路径成本
同一摞文件对应 →等价 BST 的平衡

文件内容与顺序不变,只调整摆放;平衡就是让同一批文件更易查找。

26第 26 页 · 平衡与等价的统一视角

核心概念自测

点击作答

下列关于BST旋转的描述,哪一项最准确?

27第 27 页 · 核心概念自测

本章要点回顾

  • 平衡是查找与维护之间的取舍
  • 等价BST形状不唯一,中序相同即可
  • 旋转是连接平衡与等价的桥梁
  • 严格平衡查找快,宽松平衡维护省
  • 适度平衡比理想平衡更实用
延伸主题:AVL树的插入与删除红黑树的五条性质旋转与树高的定量分析
28第 28 页 · 本章要点回顾

课后思考

先合上笔记自己想五分钟,再对照参考答案——好的思考题不在于答得'对',在于把它想透。

1严格追求'完全二叉树'那种完美平衡,每次插入都可能触发大规模重构——这种追求在实际系统中值得吗?为什么?

参考答案回到'维护代价'那张页:严格平衡每插入一次可能 O(n) 次旋转,红黑树只要 O(1) 次。完美平衡是'查询最优、维护最差',工程正解是适度平衡——在'够用'与'不过度'之间取舍。

2实际工程中,很多磁盘数据库索引并不追求严格平衡(如 AVL),而是采用更宽松的标准——为什么?这种取舍背后的物理依据是什么?

参考答案关键在物理:磁盘 I/O 远比 CPU 慢——树每矮一层 = 少一次磁盘读。所以磁盘索引宁可放宽平衡标准,也要保证'修改只触发局部调整',避免大规模写盘。算法设计必须考虑介质特性。

3等价 BST 的旋转变换保持中序遍历不变——这个'不变性'在实际中还能推出哪些有用的性质或应用场景?

参考答案推论方向:① 任意 BST 都能通过旋转变成完全二叉树(但代价 O(n) 次旋转);② 局部旋转可做范围修改、平衡修复;③ 把不变性用到极限,常常能挖出意想不到的应用场景。

29第 29 页 · 课后思考