堆排序动画演示
先把数组建成大顶堆,再逐个把堆顶换到末尾下沉回去。
键盘:← → 单步 ·空格 播放/暂停 · R 重置 ·Home/End 到两端
堆排序把数组当成一棵完全二叉树来看:下标 i 的两个孩子是 2i+1 和 2i+2,父子关系全藏在乘法里,不用一个节点的额外空间。先把数组整理成大顶堆——每个父都不小于自己的孩子,堆顶就是最大值;然后把堆顶换到末尾,堆缩小一格,让掉到根位的元素往下沉,重新维持堆序。
这一页同时给你两个视图:上面是数组的柱子,下面是同一份数据的树。下沉沿哪条边走、孩子在哪儿被比较,都在树上标出来;已经定稿的尾巴在两个视图里同时保持绿色,树里那些连向尾巴的边会压暗,表示它们已经不是堆的一部分。建堆是从 floor(n/2)−1 往下做的,叶子不用动。
堆排序演示怎么用
- 对着看:树上的 [i] 就是数组下标;柱子换了,树上的圆也跟着换值,两边永远同步。
- 认颜色:蓝色是当前正在处理的结点 k,黄色是要跟它比的孩子 c,绿色的尾巴已经出堆,路径色的高亮边是刚走下来的那条。
- 数比较:每层下沉最多比两次(孩子之间一次、父子之间一次),计数条上的数字乘上堆高就是它的真实成本。
- 看建堆:开局那一段是自底向上建堆,从最后一个非叶子结点开始;做完时 a[0] 已经是全数组最大值。
常见问题
建堆为什么是 O(n) 而不是 O(n log n)?
因为大部分结点在树的底层,它们要下沉的路径极短:一半的结点是叶子不用动,四分之一只需走一层。把每层的工作量加起来是个收敛的级数,总量线性。只对根做 n 次下沉才需要 n log n。
同样 O(n log n),为什么它常输给快排?
堆的下沉在数组里是大跨度的跳转(父亲在 i,孩子在 2i+1),访问的格子离得很远,缓存命中率很差;快排的扫描则是贴着一条连续内存走。理论上界更稳,但实测常数吃亏,加上它不稳定。
堆排序和优先队列是一回事吗?
用的是同一个结构。堆排序是建好之后只做一个动作——反复取堆顶;优先队列则是要一边插入一边取最值,得维持 up/down 两个方向的操作,所以不拿它排序,只拿它当调度、Top-K 的地基。