react 源码中堆排序的应用

本文详细介绍了React中使用最小堆(taskQueue和timerQueue)进行任务调度的优化策略。通过最小堆保证O(1)的时间复杂度获取最高优先级任务。涉及的函数包括push、peek和pop,用于节点的添加、查看和提取。siftUp和siftDown确保堆的正确性。堆结构使得在添加或删除节点后能快速调整以维持最小堆特性,从而高效地处理优先级任务。
摘要由CSDN通过智能技术生成

堆排序相关文章

  • 对于二叉堆的应用是在scheduler包中, 有 2 个数组taskQueue和timerQueue, 它们都是以最小堆的形式进行存储, 这样就能保证以O(1)的时间复杂度, 取到数组顶端的对象(优先级最高的 task).
  • 具体的调用过程被封装到了SchedulerMinHeap.js, 其中有 2 个函数siftUp,siftDown分别对应向上调整和向下调整.
  • 采用最小堆是因为react中根据bit位为1的离右边距离最近的优先级越高(即值越低),故采用最小堆的首位能提取出优先级最高的任务
type Heap = Array<Node>;
type Node = {|
  id: number,
  sortIndex: number,
|};

// 添加新节点到末尾, 添加之后, 需要调用`siftUp`函数向上调整堆,(若小则升高优先级)
export function push(heap: Heap, node: Node): void {
  const index = heap.length;
  heap.push(node);
  siftUp(heap, node, index);
}

// 查看堆的顶点, 也就是优先级最高的`task`或`timer`
export function peek(heap: Heap): Node | null {
  const first = heap[0];
  return first === undefined ? null : first;
}

// 将堆的顶点提取出来, 并替换尾顶点到首部之后, 需要调用`siftDown`函数向下调整堆.(若大则降低优先级)
export function pop(heap: Heap): Node | null {
  const first = heap[0];
  if (first !== undefined) {
    const last = heap.pop();
    if (last !== first) {
      heap[0] = last;
      siftDown(heap, last, 0);
    }
    return first;
  } else {
    return null;
  }
}

// 当插入节点之后, 需要向上调整堆结构, 保证数组是一个最小堆.
function siftUp(heap, node, i) {
  let index = i;
  while (true) {
  	//位运算,右移一位,相当于n/2,是因为根据完全二叉树找父节点的规律
    const parentIndex = (index - 1) >>> 1;
    const parent = heap[parentIndex];
    if (parent !== undefined && compare(parent, node) > 0) {
      // The parent is larger. Swap positions.
      heap[parentIndex] = node;
      heap[index] = parent;
      index = parentIndex;
    } else {
      // The parent is smaller. Exit.
      return;
    }
  }
}

// 向下调整堆结构, 保证数组是一个最小堆.
function siftDown(heap, node, i) {
  let index = i;
  const length = heap.length;
  while (index < length) {
    const leftIndex = (index + 1) * 2 - 1;
    const left = heap[leftIndex];
    const rightIndex = leftIndex + 1;
    const right = heap[rightIndex];

    // If the left or right node is smaller, swap with the smaller of those.
    //进第一个if,最后一个元素是整个树的左树的最后一个节点或右树的最后一个节点都有可能
    //因为左树最后一个节点一定比left大,右树最后一个节点也可能比left大
    if (left !== undefined && compare(left, node) < 0) {
      //取左右子树最小的节点,具体原因看上面的链接
      if (right !== undefined && compare(right, left) < 0) {
        heap[index] = right;
        heap[rightIndex] = node;
        index = rightIndex;
      } else {
        heap[index] = left;
        heap[leftIndex] = node;
        index = leftIndex;
      }
      //此处为对重新建堆的优化,即compare(left, node) > 0,说明左子树已经是最小堆了,只用比较右子树就行了
    } else if (right !== undefined && compare(right, node) < 0) {
      heap[index] = right;
      heap[rightIndex] = node;
      index = rightIndex;
    } else {
      // Neither child is smaller. Exit.
      return;
    }
  }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值