React Scheduler 最小堆实现小结

 更新时间:2026年01月27日 09:45:25   作者:_DoubleL  
本文主要介绍了React Scheduler 最小堆实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1. 什么是最小堆

最小堆(Min Heap)是一种完全二叉树结构,同时满足一个很关键的性质:任意一个节点的值,都 ≤ 它的左右子节点的值,也就是说: 👉 堆顶(根节点)一定是整个结构中最小的元素

完全二叉树的特点是:

  • 从上到下
  • 从左到右依次填满
  • 只允许最后一层不满

2. 用数组表示最小堆🔥

最小堆通常用数组实现,而不是链表。

索引:  0  1  2  3  4  5
数组: [1, 3, 5, 4, 6, 8]

如果数组下标从 0 开始:

  • 父节点:(i - 1) >>> 1;
  • 左子节点:2 * i + 1
  • 右子节点:2 * i + 2

3. React Scheduler 最小堆实现

React 的 Scheduler 内部,正是通过 最小堆 + sortIndex 来维护任务执行顺序

export type Node = {
  id: number;        // 每个任务的唯一标识
  sortIndex: number; // 决定任务顺序
};

堆的本质:数组

export type Heap<T extends Node> = Array<T>;

3.1 取出堆顶元素

export const peek = <T extends Node>(heap: Heap<T>): T | null => {
  return heap.length === 0 ? null : heap[0];
};

3.2 插入元素

插入流程:

  1. 新元素放到数组末尾
  2. 从下往上进行 堆化(siftUp),不断与父节点比较,若比父节点小就交换,一直向上,直到满足堆性质
  3. 恢复最小堆性质

如下图,在最后的节点插入1, 1和父节点(10)交换位置, 接着 1和父节点(2) 交换位置,就变成了恢复了最小堆

// 插入元素
export const push = <T extends Node>(heap: Heap<T>, node: T): void => {
  // 1. 把node放到堆的最后
  const index = heap.length;
  heap.push(node);
  // 2. 调整最小堆,从下往上堆化
  siftUp(heap, node, index);
};
​
// 从下往上堆化
export const siftUp = <T extends Node>(
  heap: Heap<T>,
  node: T,
  i: number,
): void => {
  let index = i;
​
  while (index > 0) {
    // 无符号右移,相当于 /2 并且向下取整
    const parentIndex = (index - 1) >>> 1;
    const parent = heap[parentIndex];
    // 如果父节点大于node,需要交换
    if (compare(parent, node) > 0) {
      // node子节点更小,和根节点交换
      heap[parentIndex] = node;
      heap[index] = parent;
      index = parentIndex;
    } else {
      return;
    }
  }
};
​
// 比较函数,返回值大于0 表示 a大于b
function compare(a: Node, b: Node) {
  const diff = a.sortIndex - b.sortIndex;
  return diff !== 0 ? diff : a.id - b.id;
}

3.3 删除堆顶元素

删除流程

  1. 保存堆顶元素(最小值)
  2. 取出最后一个元素
  3. 放到堆顶
  4. 从上往下堆化(siftDown),比较 node 与左右子节点,选择 更小的那个子节点,若子节点更小,则交换,一路向下,直到恢复堆序
// 删除堆顶元素  先取出堆顶元素,然后取出最后一个元素放到堆顶,然后从上往下堆化
export const pop = <T extends Node>(heap: Heap<T>): T | null => {
  if (!heap.length) return null;
  const first = heap[0];
  const last = heap.pop()!;
  if (first !== last) {
    // 证明heap中有2个或者更多个元素
    heap[0] = last;
    siftDown(heap, last, 0);
  }
  return first;
};

// 从上往下堆化
function siftDown<T extends Node>(heap: Heap<T>, node: T, i: number): void {
  let index = i;
  const length = heap.length;
  // 只需要取一半的节点,因为每次都是跟左半边 或者 右半边的节点对比
  const halfLength = length >>> 1;
  while (index < halfLength) {
    const leftIndex = (index + 1) * 2 - 1;
    const left = heap[leftIndex];
    const rightIndex = leftIndex + 1;
    const right = heap[rightIndex]; // right不一定存在,等下还要判断是否存在
    if (compare(left, node) < 0) {
      // left<node
      if (rightIndex < length && compare(right, left) < 0) {
        // right存在,且right<left
        heap[index] = right;
        heap[rightIndex] = node;
        index = rightIndex;
      } else {
        // left更小或者right不存在
        heap[index] = left;
        heap[leftIndex] = node;
        index = leftIndex;
      }
    } else if (rightIndex < length && compare(right, node) < 0) {
      // left>=node && right<node
      heap[index] = right;
      heap[rightIndex] = node;
      index = rightIndex;
    } else {
      // 根节点最小,不需要调整
      return;
    }
  }
}

// 比较函数,返回值大于0 表示 a大于b
function compare(a: Node, b: Node) {
  const diff = a.sortIndex - b.sortIndex;
  return diff !== 0 ? diff : a.id - b.id;
}

到此这篇关于React Scheduler 最小堆实现小结的文章就介绍到这了,更多相关React Scheduler 最小堆内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React 高阶组件入门介绍

    React 高阶组件入门介绍

    本篇文章主要介绍了React高阶组件入门介绍,这篇文章中我们详细的介绍了什么是高阶组件,如何使用高阶组件,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 详解React中如何拆分组件

    详解React中如何拆分组件

    这篇文章主要为大家详细介绍了React中拆分组件的相关知识,文中的示例代码讲解详细,对我们掌握React有一定的帮助,需要的小伙伴可以参考一下
    2023-12-12
  • react hooks 计数器实现代码

    react hooks 计数器实现代码

    这篇文章主要介绍了react hooks计数器实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • react源码层探究setState作用

    react源码层探究setState作用

    写react的时候,踩了几次坑发现setstate之后state不会立刻更新,于是判定setstate就是异步的方法,但是直到有一天,我想立刻拿到更新的state去传参另一个方法的时候,才问自己,为什么setstate是异步的?准确地说,在React内部机制能检测到的地方,setState就是异步的
    2022-10-10
  • React掌握openapi-typescript-codegen快速生成API客户端代码的过程

    React掌握openapi-typescript-codegen快速生成API客户端代码的过程

    openapi-typescript-codegen是一个开源工具,用于根据OpenAPI规范自动生成TypeScript代码,包括类型定义和API客户端代码,它帮助开发者节省手动编写代码的时间,提高开发效率,感兴趣的朋友一起看看吧
    2024-11-11
  • React Context跨层级通信的利器

    React Context跨层级通信的利器

    本文主要介绍了React Context跨层级通信的利器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-05-05
  • React+Antd修改Table组件滚动条样式的操作代码

    React+Antd修改Table组件滚动条样式的操作代码

    这篇文章主要介绍了React+Antd修改Table组件滚动条样式的操作代码,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • React获取setState更新后值的多种方案

    React获取setState更新后值的多种方案

    在React开发中,很多新手都会遇到一个常见坑:调用setState更新状态后,立即读取状态却拿到旧值,本文将从问题本质出发,分类详解类组件和函数组件中获取setState更新后值的多种方案,需要的朋友可以参考下
    2025-12-12
  • React闭包陷阱产生和解决小结

    React闭包陷阱产生和解决小结

    闭包陷阱是一个常见的问题,尤其是在处理异步操作、事件处理器、或是定时器时,本文就来介绍一下React闭包陷阱产生和解决小结,具有一定的参考价值,感兴趣的可以了解一下
    2025-04-04
  • ReactNative列表ListView的用法

    ReactNative列表ListView的用法

    本篇文章主要介绍了ReactNative列表ListView的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08

最新评论