二叉堆动画演示

完全二叉树摊平进数组,父不小于子,上浮下沉维持秩序。

键盘:← → 单步 ·空格 播放/暂停 · R 重置 ·Home/End 到两端

二叉堆是一棵完全二叉树,摊平放进数组后不用存任何指针:下标 i 的父亲是 (i-1)/2,两个孩子是 2i+1 与 2i+2,算术就是树结构。它只保证「父比子更优先」,不保证左右谁大,所以它不是排序好的数组,而是每次只把最值得先处理的那一个放在堆顶。

这一页把三个动作分开:自底向上建堆不是从根往下插,而是从最后一个非叶节点开始逐个下沉,因为叶子本身已经满足性质,这样算下来总代价是 O(n) 而不是 O(n log n);插入接在末尾那层空位,再一路和父亲比、必要时上浮;删堆顶时先把堆顶和末尾互换、缩短数组,再让新的堆顶下沉,树不会缺一块。切换大顶堆与小顶堆只改一个比较方向,走法完全不同。

二叉堆演示怎么用

  • 两个视图对照:上面是数组柱子,下面是同一批数据的树,两边用同一套下标编号。柱子换值时树上的数字同步变化,算术与树形的对应关系不用自己在脑子里换算。
  • 切堆类型:堆类型条选大顶或小顶。同一份数据切换后,比较方向反过来,下沉与上浮的路径也会整段改变。
  • 看下沉与上浮:每轮比较都会把父与将要当选的孩子同时染色,孩子里谁更优先在 note 里点名;换完继续往下看它的孩子,直到停住或走到叶子层。
  • 换数据形态:规模、形态、自定义数据都照常可用,倒序与多重复会让建堆阶段的下沉次数明显不同,计数条里能直接比。

常见问题

为什么自底向上建堆是 O(n)?

大部分节点都挤在下面几层,下沉的距离很短:叶子不用动,倒数第二层最多沉一步。把每层节点数乘以下沉距离加起来,级数收敛到与 n 同阶,而不像逐个插入那样每个都要走 log n。

堆和排序有什么关系?

堆排序就是先建堆、再把堆顶逐个换到尾部并下沉,原地拿到有序数组。但普通排序会把全部关系都排好,堆只维护「谁最优先」这一条,所以只要前 k 个时堆更划算。

为什么删除堆顶要先和末尾互换?

直接删掉堆顶会留一个洞,完全二叉树的数组关系立刻失效。和末尾互换后,被删元素跑到最后一个下标,数组长度减一,形状还是满的,再把上来的元素下沉修补就行。

top-k 问题为什么用堆,不直接排序?

排序要把 n 个元素全部排好,是 O(n log n) 且要知道全量;用大小为 k 的堆边看边维护,每来一个元素只和堆顶比一次,代价 O(n log k),还能处理流式到来的数据。

演示编号 B06无需安装,手机端同样可用按 Ctrl + K 搜工具与演示