堆排序相关文章
- 对于二叉堆的应用是在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,
|};
export function push(heap: Heap, node: Node): void {
const index = heap.length;
heap.push(node);
siftUp(heap, node, index);
}
export function peek(heap: Heap): Node | null {
const first = heap[0];
return first === undefined ? null : first;
}
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) {
const parentIndex = (index - 1) >>> 1;
const parent = heap[parentIndex];
if (parent !== undefined && compare(parent, node) > 0) {
heap[parentIndex] = node;
heap[index] = parent;
index = parentIndex;
} else {
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 (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;
}
} else if (right !== undefined && compare(right, node) < 0) {
heap[index] = right;
heap[rightIndex] = node;
index = rightIndex;
} else {
return;
}
}
}
- peek函数: 查看堆的顶点, 也就是优先级最高的task或timer.
- pop函数: 将堆的顶点提取出来, 并替换顶点之后, 需要调用siftDown函数向下调整堆.
- push函数: 添加新节点, 添加之后, 需要调用siftUp函数向上调整堆.
- siftDown函数: 向下调整堆结构, 保证数组是一个最小堆.
- siftUp函数: 当插入节点之后, 需要向上调整堆结构, 保证数组是一个最小堆.