3

First of all, let's spit first. The recent interview is really difficult! More and more questions are asked about the source code part and the algorithm part of the front-end interview.

In the four interviews last month, I was asked twice about the data structure of the priority queue ; fortunately, I have seen some of the scheduler part of the React source code before and have some understanding of the small top heap , and I am ambiguous. Talk about the data structure of heap and how to implement it with JS;

Front end and priority queue

If you have read the Scheduler part of the React source code, you should have an impression of the timerQueue delay queue and the taskQueue executable queue . They are both implemented using the priority queue data structure of the small top heap . For details, see "Relearning React" Why do you need Scheduler? In the Scheduler part, these two queues mainly achieve the priority sorting of tasks after scheduling (time dimension);

Priority queue and heap

As the name suggests, the priority queue is a queue . The queue has a principle of dequeuing from the head and entering the queue from the tail; and the priority queue is the maximum (large top heap) or the minimum value (small top heap) every time the priority queue is dequeued and entered, so priority is given to the queue. A queue is actually a heap too. A heap is a data structure that approximates a complete binary tree . A heap can be regarded as an array. A heap is actually a one-dimensional array maintained by the structure of a complete binary tree. It can be divided into large top heap and small top heap according to different sorting methods.

  • Big top heap: the value of each node is greater than or equal to the value of its left and right child nodes
  • Small top heap: the value of each node is less than or equal to the value of its left and right child nodes

顶堆.png

If the array data in the heap above is mapped to the array, it looks like this

 //大顶堆
[50,45,40,20,25,35,30,10,15]
//小顶堆
[10,20,15,25,50,30,40,35,45]

Therefore, we can draw the following two formulas based on the node value of the above heap and the subscript in the array

Big top heap: arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

Small top heap: arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

How to create a heap?

If we now have an unordered array of pure numbers, how would we heapsort it? Suppose we now have an unordered array
`[3, 7, 16, 10, 21, 23]
'We need to heapsort him (big top heap) so what do we need to do?

We need to adjust from bottom to top starting from the last sub-leaf node ;

Q: How to find the last sub-leaf node?

A: Because we use a one-dimensional array to store the data in the heap, we can take the length of the array + 1/2 and take the integer -1. Assuming our array is named array, you can apply the formula to the last paging child node = ( array.length+1)%2 - 1

**Compare the value of the current node with the value of the left subtree node, if the current node is less than the value of the left subtree, swap the current node and the left subtree;
After the swap, check whether the left subtree satisfies the properties of the big top heap, if not, readjust the subtree structure;**

** Then compare the value of the current node and the value of the right subtree node, if the current node is less than the value of the right subtree, swap the current node and the right subtree;
After the swap, check whether the right subtree satisfies the properties of the big top heap, if not, readjust the subtree structure;**

When no swap adjustment is required, the large top heap is built

The pictures and content are excerpted from the construction and sorting process of the large top heap
121212.png

How to create a heap with JS?

 const createHeap = (arr,)=>{
    const length = arr.length
    //如果数组长度为0或者1则不改变数组直接返回(无需比较)
    if (length <= 1) return arr
    //通过数组下标遍历
    for (let i = 1; i < length; i++) {
        while (i) {
            // 通过传入的数组下标获取父级节点数组下标并进行比对替换
            const parentIndex = Math.floor ((i - 1) / 2)

            //若当前数组下标对应的索引值大于父级节点索引值对应的值则替换
            //如果需要创建的是一个小顶堆则arr[i]<arr[parentIndex]
            if (arr[i]>arr[parentIndex]) {
                //利用解构赋值进行值替换
                [arr[i], arr[parentIndex]] = [arr[parentIndex], arr[i]]
                //替换完成将当前i替换成父级下标,减少比对
                i = parentIndex
            } else {
                //所有替换完成直接退出当前循环
                break
            }
        }
    }
}

How to insert data into the heap?

The above is the process of JS implementing a heap, so now suppose that if we need to insert a piece of data into the heap at this time, what should we do?

The heap is a priority queue, so every time we insert or remove elements, we dequeue from the head and enter the queue from the tail; we need to compare and maintain the queue at each step;
Insert operation as shown below

image.png

image.png

image.png

So we can insert new elements at the end of the queue first, and then use createHeap to compare

 const push = (arr,value)=>{
    arr.push(value)
    createHeap(arr)
    return arr
}

Header element out of heap operation

Because the priority queue is popped by the tail inserted into the head, if we need to pop an element, it will be popped from the head, what should we do?
First we pop the head element, then fill the tail element to the head

image.png

Then we compare the head element with the left and right child nodes respectively. If only one side meets the condition, replace it with the one that meets the condition. If both sides meet the condition, then replace it with the larger (or smaller, depending on whether it is a large top heap or a small one. The top stack) is swapped;

As shown in the figure below, 9 is compared with 13 and 15, all meet the conditions, 15 is greater than 13, so it is swapped with 15
image.png

Then 9 is compared with the child node. Compared with 8, it does not meet the exchange conditions, and compared with 14, it meets the exchange conditions, so it is swapped with 14;
image.png

So how to do it with js?

 //注意:需传入已创建队列而不是数组
const peek = (arr)=>{
    const length = arr.length
    //若数组为空则直接返回null
    if (!arr.length) return null
    //若数组只有一个元素则直接弹出返回这个元素
    if (length === 1) return arr.pop()
    const top = arr[0]
    //将底部子节点赋值到顶部节点
    arr[0] = arr.pop ()
    let index = 0
    const lastIndex = length - 1
    while (index < lastIndex) {
        let findIndex = index
        let leftIndex = index * 2 + 1
        let rightIndex = index * 2 + 2
        //如果左侧子节点值大于父节点则进行节点对调(小顶堆为arr[leftIndex]<arr[findIndex])
        if (leftIndex <= lastIndex && arr[leftIndex]> arr[findIndex]) {
            findIndex = leftIndex
        }
        //如果右侧子节点值大于父节点则进行节点对调(小顶堆为arr[leftIndex]<arr[findIndex])
        if (rightIndex <= lastIndex && arr[rightIndex]>arr[findIndex]) {
            findIndex = rightIndex
        }

        //注:以上两步有都执行的可能,但是目的都是为了将最大(或者最小)节点兑换到父节点,所以不影响

        //如果findIndex > index则说明子节点值大于父节点需要进行对调,对调完成之后需要从子节点进行比较因此需要index = findIndex
        if (findIndex > index) {
            [arr[findIndex], arr[index]] = [arr[index], arr[findIndex]]
            index = findIndex
        } else {
            // 不符合对调条件,跳出循环
            break
        }
    }
    return top
}
peek(arr)

龙骑士尹道长
58 声望2 粉丝

什么都不会,光会写bug