前端会用到的数据结构--堆(HEAP)

堆是什么?

  1. 完全二叉树

    1. 除最后一层外,每层都填满
    2. 用数组存储非常高效,父子节点下标有规律
  2. 堆顶始终是最大或最小的数,便于快速取出。

应用场景

1️⃣ 堆排序(Heap Sort)

原理:构建一个最大堆,每次取堆顶元素(最大),放到数组末尾,重复堆化。

时间复杂度:O(n log k)

📌 应用:

  • 在一万条数据里,取最大的10个数
  • React 内部 reconciler 中有对 fiber list 的优先级调整过程(虽然更复杂)

2️⃣ React 的 scheduler 中的最小堆队列

React 17+ 中的 scheduler 模块用于调度更新任务,其核心是一个时间驱动的优先级队列

源码地址:

arduino 复制代码
js
复制编辑
const taskQueue = new HeapQueue();   // 按照 expirationTime 排序(时间优先)
const timerQueue = new HeapQueue();  // 按照 startTime 排序(定时任务)

这里使用的是 最小堆,以保证:

  • 取出最早过期或最早开始的任务是 O(1)
  • 插入/更新任务是 O(log n)

📌 相关概念:

  • expirationTime 决定任务的紧急程度(Lanes机制)
  • startTime 控制任务延迟开始(如 setTimeout

3️⃣ 前端动画调度器(如 requestIdleCallback polyfill)

浏览器的 requestIdleCallback 用于在浏览器空闲时间运行回调,类似的调度器内部也常用最小堆存储任务(按照预定的执行时间排序),例如:

yaml 复制代码
js
复制编辑
[
  { callback: fn1, time: 158000001 },
  { callback: fn2, time: 158000003 }
]

每一帧取出堆顶执行任务(即将过期的),其余任务继续等待。


4️⃣ 优先级任务队列 / 限流工具

你实现一个并发请求池(如 5 并发),但需要支持优先级调度,可用最大堆实现优先级队列:

javascript 复制代码
js
复制编辑
class Task {
  constructor(priority, callback) { ... }
}

堆顶是优先级最高的任务,先执行它。

📌 应用:

  • 文件上传任务队列(优先级)
  • 渲染任务(长列表懒加载)

5️⃣ 前端游戏 / 动画帧控制系统

在复杂的 WebGL、canvas 动画或游戏循环中,需要按执行时间调度任务帧 ------ 最小堆非常适合做这种"时间轴排序"。

例如:

scss 复制代码
js
复制编辑
scheduleAt(time, callback)

内部将任务按时间压入最小堆,当前帧时间到了就从堆顶拿任务执行。


为什么前端常用"最小堆"?

  • 因为前端调度大多数以**"时间驱动"或"优先级最小者先执行"**为主:

    • 比如:任务最早执行、超时最早发生、优先级最小者最紧急
  • 所以最小堆正好满足这个模型:堆顶是最小值,取用只要 O(1)


如何实现堆?

  • peek函数: 查看堆的顶点, 也就是优先级最高的tasktimer.
  • pop函数: 将堆的顶点提取出来, 并删除顶点之后, 需要调用siftDown函数向下调整堆.
  • push函数: 添加新节点, 添加之后, 需要调用siftUp函数向上调整堆.
  • siftDown函数: 向下调整堆结构, 保证数组是一个最小堆.
  • siftUp函数: 当插入节点之后, 需要向上调整堆结构, 保证数组是一个最小堆.

总结

面试官问:堆在前端有什么应用?
在前端开发中,堆主要应用在需要快速获取"最小/最大值"的任务调度场景中。例如:

  • React 中的 scheduler 模块使用最小堆管理任务队列,以 O(1) 获取优先级最高的任务
  • requestIdleCallback 的 polyfill 实现中,也会用最小堆安排任务执行时间
  • 自定义的并发任务队列(如上传、抓取)也可用最大堆做优先级控制
  • 当然,堆排序本身也可以用来实现稳定的 O(n log k) 排序

因为堆能在 log(n) 时间内插入任务,O(1) 获取最小值,所以非常适合调度类系统。

相关推荐
ClouGence1 分钟前
AI Agent 能写测试、跑流程,为什么回归测试还不能完全交给 AI?
前端·测试
码云之上2 分钟前
Context Engineering:让 Agent 在当前步骤看到正确的事实
前端·人工智能·前端工程化
嘟嘟071722 分钟前
从手写 HashRouter 到 React Router:逐层拆解 SPA 前端路由的完整实现
前端·javascript
我叫蒙奇1 小时前
JS中的隐式类型转换
前端
他们叫我秃子1 小时前
前端开发转 Go 全栈(四):代码写在前面,却要最后执行?我终于搞懂了 defer
前端·后端·go
生戎马 平安京策1 小时前
只学一点点:我的技术学习策略
前端·javascript·react.js
大鹏说大话2 小时前
HTML5 地理定位 Geolocation:获取用户位置的“红线”与最佳实践
前端·html·html5
Csvn2 小时前
content-visibility: auto —— 让浏览器跳过离屏渲染的性能黑科技
前端
小鹰信息技术服务部2 小时前
Edge安装包MicrosoftEdgeSetup.exe无法运行,点击没反应
前端·edge
webkubor3 小时前
一次前端生产白屏复盘:旧 HTML、Hash 资源和 MIME type text/html
前端·前端工程化