准备开一个React系列,主要是记录和复习学习React源码,因为确实很容易忘记
目前打算从调度算法开始这个系列,个人认为在学习调度算法之前最好了解一下最小堆,所以先写一个关于最小堆的介绍,以便后边的理解
最小堆前置知识
在了解最小堆之前,有必要先了解二叉树
二叉树:
二叉树是树种的每一个节点的子节点个数都小于等于2的树 二叉树又分为两种:满二叉树和完全二叉树
满二叉树:
如果一棵二叉树只有度为0的节点和度为2的节点,并且节点为0的节点都在同一层,则称为满二叉树
完全二叉树:
除了最低层外,每一层都已经填满,并且最下面一层的节点都集中在最左边的位置(只有右边存在连续的空位)
其下标满足规律:parentIndex = (childIndex - 1) >>> 1、leftIndex = (index +1 )*2 - 1、rightIndex = leftIndex + 1
堆其实是一棵完全二叉树,同时保证父子节点的顺序关系
最小堆
最小堆是一个经过排序的完全二叉树,其任一非终端节点的数值都不大于其左右节点 根据上边发现的完全二叉树的下标规律,那我们可以尝试完成最小堆的增删查了
查
获取最小堆的堆顶值
function peek<T>(heap:Heap<T>):T|null{
return heap.length>0?heap[0]:null;
}
添加
往最小堆中添加元素,一般是将新元素插入数组的尾部,然后从堆低向上调整
怎么调整呢?
最小堆的特点就是父节点比左右两个节点都小,那我们现在最多只有最末尾新增的元素不满足,那我们就一直判断,然后向上调整就可以了
function push<T>(heap: Heap<T>, node: T):void{
let index = heap.length;
heap.push(node);
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (heap[parentIndex] <= heap[index]) break;
[heap[parentIndex], heap[index]] = [heap[index], heap[parentIndex]];
index = parentIndex;
}
}
删除堆顶元素
当React执行完某一个任务时候,将该任务从队列中删除,即将队列的第一个元素删除
那怎么调整呢?
我们可以将最末尾的元素提到堆顶,然后从堆顶向下调整,原理呢和上面差不多,都是要抓住最小堆的重要特征父节点比左右两个节点都小
function pop<T>(heap:Heap<T>): T | null {
if (heap.length === 0) return null;
const root = heap[0];
const last = heap.pop();
if (heap.length > 0 && last !== undefined) {
heap[0] = last;
siftDown(heap, 0);
}
return root;
}
function siftDown<T>(heap:Heap<T>, index:number) {
const leftChildIndex = 2 * index + 1;
const rightChildIndex = 2 * index + 2;
let smallestIndex = index;
if (leftChildIndex < heap.length && heap[leftChildIndex] < heap[smallestIndex]) {
smallestIndex = leftChildIndex;
}
if (rightChildIndex < heap.length && heap[rightChildIndex] < heap[smallestIndex]) {
smallestIndex = rightChildIndex;
}
if (smallestIndex !== index) {
[heap[index], heap[smallestIndex]] = [heap[smallestIndex], heap[index]];
siftDown(heap, smallestIndex);
}
return;
}
关于调度算法中涉及的最小堆部分也差不多了,那我们下一节再见 希望本文对您有所帮助,如果有任何错误,欢迎指出,十分感谢💖💖💖