堆排序核心是上浮与下沉:新元素插入时通过父节点下标(index−1)/2上浮调整;堆顶替换后从根节点依2×index+1/2子节点下沉重建;建堆推荐自底向上下沉法(o(n)),排序时交换堆顶与末尾、缩容、再下沉。

堆排序的核心不在“排序”本身,而在两个基础动作:元素插入时的上浮(Heapify Up)和堆顶替换后的下沉(Heapify Down)。整个过程不依赖树形结构的显式构建,全部通过数组下标运算完成——本质是用线性存储模拟完全二叉树关系。
上浮调整:新元素如何“冒泡”到正确位置
当一个新元素加入堆末尾(即数组最后一个位置),它可能破坏堆序性。此时需沿父路径向上比较、交换,直到满足堆性质。
- 设当前元素下标为 index,其父节点下标恒为 (index − 1) / 2(整除)
- 对大根堆:若
arr[index] > arr[(index−1)/2],则交换,并将 index 更新为父下标,继续上溯 - 终止条件:到达根节点(index == 0)或不再大于父节点
- 单次上浮最坏耗时 O(log n),因路径长度等于树高
下沉调整:堆顶失效后如何“沉降”重建秩序
删除堆顶(如排序中把最大值换到末尾)后,原末尾元素被提至根位,大概率不满足堆性质。需从根开始向下逐层比较、交换,使其“沉”到合适位置。
- 设当前处理下标为 index,左子节点为 2×index + 1,右子为 2×index + 2
- 在左右子中选出较大者(大根堆)或较小者(小根堆),再与当前节点比较
- 若当前节点小于(大根堆)该极值,则交换;否则停止
- 交换后更新 index 为被选子节点下标,重复上述过程
- 边界控制:子节点下标必须 (当前有效堆长度)
建堆阶段:为何推荐从底向上下沉而非逐个上浮
初始数组转为堆,有两种策略:
- 逐个上浮建堆:遍历数组,对每个新元素调用上浮逻辑。时间复杂度 O(n log n)
- 自底向下下沉建堆:从最后一个非叶子节点(下标 arr.length/2 − 1)开始,向前依次对每个父节点执行下沉操作。利用完全二叉树节点分布特性,总时间可优化至 O(n)
- 实践中后者更高效,尤其数据量大时。关键点在于:叶子节点天然满足堆性质,无需调整;只须修复所有非叶子节点的局部堆序
排序主循环:交换 + 缩容 + 下沉三步闭环
升序排列使用大根堆,每轮固定一个最大值到末尾:
- 将堆顶 arr[0] 与当前堆尾 arr[heapSize−1] 交换
- 令 heapSize−−,缩小有效堆范围(已就位元素不再参与调整)
- 对新的堆顶(原尾部元素)执行一次下沉操作,恢复剩余部分的大根堆性质
- 重复直至 heapSize ≤ 1,排序完成











