(xa1)左式堆:结构

官官方信息技术老师·12 页·深入(追求细节与边界)·0 次浏览·38 天前
优先队列数据结构堆合并零距离

左式堆:结构

看完你能画出左式堆结构并解释 npl 与左右旋转的设计动机

按 空格/→ 演示下一步

问一句
1 / 12 页

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

优先队列数据结构堆合并零距离

左式堆:结构

看完你能画出左式堆结构并解释 npl 与左右旋转的设计动机

1第 1 页 · 左式堆:结构

第一印象

见过挂满装饰、一侧沉甸甸的圣诞树吗?枝条全往一边伸,看着歪,却站得稳。左式堆就是这棵「刻意偏斜」的树:堆性质照旧,但形状故意不对称。

仍是二叉树
每个节点最多两个孩子,满足堆有序
左倾外形
左子树总是更深,节点像挂满一侧的枝条
不追求平衡
AVL 追求左右对称,左式堆反而故意偏斜
偏斜的圣诞树对应 →左式堆

树的重载一侧对应堆的左深子树

2第 2 页 · 第一印象

堆之合并

插入删除二者都擅长,可一旦要合并两个堆,普通二叉堆立刻暴露软肋——这正是左式堆的出场理由。

二叉堆的合并
  • 底层是数组,靠下标定位父子
  • 合并需把两堆元素全部重排
  • n+m 个元素重建,代价 O(n+m)
左式堆的合并
  • 底层是指针树,沿右路径行走
  • 合并只拆右路径上的子树
  • 右路径长 O(log n),代价对数级
频繁插入删除选二叉堆;需要反复合并(如可并优先队列、图算法)时选左式堆。
3第 3 页 · 堆之合并

奇中求正

上一页看到:普通堆合并只能逐个插入,太慢。想让合并快,就得让合并只碰一小部分节点——能不能把树设计成「偏」的,让短的那条路天然可以被沿着走?

零位路径长度 npl
从节点到最近一个空孩子的最短距离,空节点记 0
左偏性质
每个节点左孩子的 npl ≥ 右孩子的 npl
右路径短
npl 为 n 的子树至少含 2^n−1 个节点,右路径必为 O(log n)
合并沿右路径
只走右脊柱归并,再交换失衡子树,O(log n) 搞定
惯用左手的人对应 →左式堆

重活都堆在左边,右边只留最短的通道供合并快速穿行

4第 4 页 · 奇中求正

NPL:空节点路径长度

上一页看到左式堆「往左沉」的怪长相。但多深才算够左?总得有个尺子。这把尺子叫 npl:从节点出发,走到最近的「缺儿子」位置要几步。

外部节点
虚构的空儿子节点,npl 为 0,作计算的落脚点
npl 定义
x 到最近外部节点的最短路径长度
叶子边界
叶子的儿子全是外部节点,故 npl = 1
递推规则
npl 取左右子树较小值加一,只看短的那边
楼道到出口的距离对应 →npl

从每个房间到最近安全出口的步数,就是该房间的 npl

npl(x)={0x=null1+min⁡(npl(l), npl(r))其余npl(x)=\begin{cases}0 & x=\text{null}\\ 1+\min\big(npl(l),\,npl(r)\big) & \text{其余}\end{cases}
5第 5 页 · NPL:空节点路径长度

NPL 的递归计算

npl(x) 取左右子树 npl 的最小值加一,逐层递归向上算出。

1
空节点记 0
递归到底:null 节点的 npl 定义为 0,这是递归出口
2
叶节点
叶节点左右均为空,min(0,0)+1=1
3
单子节点
缺的一侧按空节点算,min(npl子, 0)+1=1
4
内部节点
取左右孩子 npl 的较小值加一,逐层上推
5
回溯验证
沿任一路径向上验证:npl 值比最浅孩子多一
6第 6 页 · NPL 的递归计算

左倾性

每个节点旁标注 NPL 值,对照左右孩子大小,验证左式堆的核心不等式。

图解渲染中…
i1:空孩子视为 NPL=0,这是递归计算的边界条件h1:叶子节点 NPL 恒为 0,两边相等即满足不等式
7第 7 页 · 左倾性

自测:npl 判定

点击作答

一棵二叉树每个节点都满足 npl(左孩子) ≥ npl(右孩子),能否断定它是合法的左式堆?

8第 8 页 · 自测:npl 判定

左展右敛的形态

这是一棵左式堆:沿左侧越走越深,右侧很快见底,整体左重右轻。

图解渲染中…
a1:根节点,标注为「键值 npl值」f1:空子树,npl 定义为 0 的来源
9第 9 页 · 左展右敛的形态

结构性质的推论

上一页我们看到左式堆整体左沉右浅,但这种形态不是巧合,而是每一步插入合并时被强制维持的结果。形态被约束,就有代价可算——最直接的受益者,就是那条最短的右侧路径。

右路径够短
右子树沿右链最短,一切高效合并都走它
上界 O(log n)
右链上 npl 递减,故右链长不超过 O(log n)
整体未必平衡
左子树可以很深,左式堆不保证全树平衡
所有操作沿右路
合并、插入、删除都只需接触右路径
靠右行驶的快车道对应 →右侧路径

车流集中在右侧快速通过,左侧慢车道再长也不影响通行

∣right path∣≤⌊log⁡2(n+1)⌋|\text{right path}| \le \lfloor \log_2(n+1) \rfloor
10第 10 页 · 结构性质的推论

收束要点

  • ✓合并需求是左式堆一切设计的源头
  • ✓NPL 用递归定义:空节点为 0,父为子最小加一
  • ✓左倾性保证右孩子 NPL 最短,合并路径 O(log n)
  • ✓右路径短靠左倾性,不是靠平衡性
  • ✓判断形态:右链长度不超过 O(log n) 即合格
延伸主题:左式堆的合并算法实现插入与删除为何都归结为合并斜堆与左式堆的对比
11第 11 页 · 收束要点

课后思考

先合上笔记自己想一会儿,再对照参考答案。

1左式堆为什么把最短路径压在左侧,而不是右侧?换成右倾会有什么代价?

参考答案关键在合并:合并沿右侧路径走。左倾保证右路径最短,合并代价 O(log n);若右倾,右侧路径可能长达 O(n),合并退化为线性。

2斜堆等结构没有 npl 约束也能 O(log n) 合并,左式堆的额外维护换来了什么?

参考答案左式堆有 npl 保证最坏情形 O(log n);斜堆只靠均摊分析,单次合并最坏可到 O(n)。左式堆换来的是可预测的性能上界。

3如果把左式堆的合并搬到外存或并发场景,'沿右路径递归'这条路还走得通吗?

参考答案右路径虽短但更新会回溯修改沿途节点,随机访问多、写冲突重。外存场景可考虑按右路径分批缓冲,并发则需沿途加锁或改用无锁结构。

12第 12 页 · 课后思考
(xa1)左式堆:结构 · 知识图解