Appearance
题目
在将数据序列 (6, 1, 5, 9, 8, 4, 7) 建成大根堆时,正确的序列变化过程是()。
错因
B
调整方向反了:B 的第一步是 6,9,5,1,8,4,7 ——这相当于先调整了下标 2 的结点(值 1,孩子 9 和 8),让 9 上浮。但建堆的标准做法是从最后一个非叶(下标 )出发自底向上 sift-down,先处理深的、再处理浅的。下标 2 比下标 3(值 5,孩子 4 和 7)更靠近根,应该后处理。B 调反了顺序,先动浅的,再动深的。
C
和 B 同源——首步同样是先调下标 2,然后才回头调下标 3。整个调整顺序变成"上 → 上 → 下 → 上",跳过了"先把所有非叶按下标从大到小依次下沉"这条铁律。即使最终堆形态是对的,过程也违反算法定义。
D
D 的第一步对(处理下标 3:5 与 7 互换得 6,1,7,9,8,4,5),但第二步不该调下标 1 而该调下标 2。D 跳过了下标 2(值 1),直接把根 6 与右孩 7 交换,结果上方还残留 1(值很小)压着 9,违反"自下往上"原则——必须先在下标 2 处把 1 沉下去,再处理根。这是对"建堆从哪开始"和"上一步先做什么"两件事都没读对。
总解析
建堆算法(自底向上 sift-down 法):把数组当成完全二叉树,从最后一个非叶结点(下标 ,1-based 下标体系)开始,逐个向前对每个结点做"向下调整"。每次调整就是:与较大的孩子比较,若孩子更大则交换并继续向下沉,直到下沉到比两个孩子都大或到达叶层为止。
初始序列(下标 1–7):6, 1, 5, 9, 8, 4, 7,对应完全二叉树:
6 (1)
/ \
1 (2) 5 (3)
/ \ / \
9 (4) 8(5) 4(6) 7(7),最后非叶结点下标 。从下标 3 开始向前调到下标 1。
第 1 步:调整下标 3(值 5)
孩子是下标 6(=4)和下标 7(=7)。较大的孩子是 7,且 ,交换。
结果:6, 1, 7, 9, 8, 4, 5(A 的第一帧)。下标 3 现在是 7,下方只剩值 5 这片叶子,调整结束。
第 2 步:调整下标 2(值 1)
孩子是下标 4(=9)和下标 5(=8)。较大的孩子是 9,且 ,交换。
结果:6, 9, 7, 1, 8, 4, 5(A 的第二帧)。下标 4 现在是 1,它已是叶(下标 8 越界),调整结束。
第 3 步:调整下标 1(值 6)
孩子是下标 2(=9)和下标 3(=7)。较大的孩子是 9,,交换。
结果:9, 6, 7, 1, 8, 4, 5(A 的第三帧)。值 6 落到下标 2,继续向下沉:孩子是下标 4(=1)和下标 5(=8)。较大孩子是 8,,再交换。
结果:9, 8, 7, 1, 6, 4, 5(A 的第四帧)。值 6 落到下标 5,已是叶,调整结束。
最终大根堆:
9 (1)
/ \
8 (2) 7 (3)
/ \ / \
1 (4) 6(5) 4(6) 5(7)每个父结点都 ≥ 其孩子,验证无误。整个变化过程恰好对应选项 A 给出的四帧。
最终答案是 A。