完全二叉堆:结构
看完你能画出任一数组的堆形态,并说清数组为何能存树
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
完全二叉堆:结构
看完你能画出任一数组的堆形态,并说清数组为何能存树
为什么需要堆
前页看到:有序数组取最值快但插入慢,无序数组插入快但取最值慢。鱼与熊掌都想占,就需要一种新的组织方式——让「找最值」和「插入」都快,这就是堆要解决的问题。
总裁在最顶层对应最值总在堆顶,逐层下管对应父子偏序
什么是完全二叉树
上一页说了堆要支持「随时找最值」,这就要求树必须长得规整、不能歪。先看规整的标准:想象排队上电梯,一层站满才开下一层,这就是完全二叉树的画法。
前排坐满才坐下一排,末排从左往右依次坐
完全 vs 满满 vs 一般
从「二叉树家族」出发,向下看三类成员各自的形状约束:满树最严,完全树次之,一般树最自由。
结构性:堆的形
上一页我们区分了完全二叉树和满二叉树。堆要的正是完全二叉树这个形状:除最底层外每层都填满,最底层从左往右排。这个约束不是为了好看,它直接决定了堆怎么存、怎么插。
书架上层必须摆满,最下层也只能从左端连续摆
父子的下标关系
把堆的树形画成数组:先看节点 0 的两个孩子落在哪,再看任意节点 i 的通用公式。
向量中的堆
用一小段代码验证:堆不用指针,父子关系全靠下标算出来。
下标 i 从 0 起:(i-1)//2 定位父,2i+1、2i+2 定位左右孩子;层序铺进向量后,整棵树形不用任何指针即可还原。
形具神备
前页我们看到堆在数组里排列成完全二叉树。但光有树形还不够——若父节点比子节点小,取最值就失效。形已具备,还需神的约束:堆序性。
组织结构图对应结构性,职级上下级对应堆序性
堆序性:大小的次序
上一页我们确定了堆的「形」:一棵装在向量里的完全二叉树。但光有形状还不够——树里各处该放什么值?堆序性给出约束:只规定父子间的大小关系,不追求全排序。
职级只约束上下级:上级不低于直接下属,同级之间互不比较
堆序 ≠ 全序
看箭头方向:每个孩子都指向小于自己的父亲,但兄弟之间没有箭头约定。
自测:这棵树是堆吗
一棵完全二叉树,每个结点都大于等于它的子结点。它是堆吗?
小结:形与神
- ✓完全二叉树保证树矮而整齐,这是堆的『形』
- ✓堆序性保证父子大小关系,这是堆的『神』
- ✓形与神合一,堆才成立,缺一不可
- ✓数组下标即可描述父子关系,无需指针
- ✓堆只约束局部次序,不是全序结构
课后思考
先自己想几分钟,再对照参考答案,看思路是否一致。
参考答案从两头想:满二叉树太苛刻,节点数必须恰好 2^h−1,装不下任意 n;一般二叉树会歪,无法紧凑排列。完全二叉树层次整齐又能容纳任意 n,还能无缝映射进数组。
参考答案下标关系本质是数组按层编号带来的,换链表就没了下标。链表里只能存指针,需额外字段,且失去按 i/2、2i 直接定位的 O(1) 便利。
参考答案d 叉堆:父 i 的孩子是 d·i+1 … d·i+d,父是 ⌊(i−1)/d⌋。树更矮,但下沉时比较变多。d 大时未必划算,要按场景权衡。