前端会用到的数据结构--堆(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) 获取最小值,所以非常适合调度类系统。

相关推荐
AI视觉网奇几秒前
音频获取长度
java·前端·python
小喷友40 分钟前
第 6 章:API 路由(后端能力)
前端·react.js·next.js
像素之间43 分钟前
elementui中rules的validator 用法
前端·javascript·elementui
小高0071 小时前
🚀把 async/await 拆成 4 块乐高!面试官当场鼓掌👏
前端·javascript·面试
CF14年老兵1 小时前
SQL 是什么?初学者完全指南
前端·后端·sql
2401_837088501 小时前
AJAX快速入门 - 四个核心步骤
前端·javascript·ajax
一月是个猫1 小时前
前端工程化之Lint工具链
前端
小潘同学1 小时前
less 和 sass的区别
前端
无羡仙1 小时前
当点击链接不再刷新页面
前端·javascript·html
王小发1011 小时前
快速知道 canvas 来进行微信网页视频无限循环播放的思路
前端