关于堆的知识点你都了解吗?

314 阅读2分钟

堆这个数据结构在面试中经常被面试官Q到,所以有关堆的一些知识,我们有必要进行掌握。

首先堆(heap) 也是一个数据结构,它分为大顶堆和小顶堆:

大顶堆: 节点值大于等于其左右子节点的值

小顶堆: 节点值小于等于左右子节点的值

用数学表达式表示就是

小顶堆 a[i]<=a[2*i+1] && a[i]<= a[2*i+2]

大顶堆 a[i]>=a[2*i+1] && a[i]>= a[2*i+2]

堆排序

堆排序其实是利用堆这种数据结构而设计的排序算法,

时间复杂度: O(nlogn)

算法思路

将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

比如给出无序数组 arr= [9,5,3,6,2]

构建堆

  1. 我们可以先把数组以二叉树的形式写出来,然后按照大顶堆的形式将二叉树结构进行改造,从第一个非叶子节点开始,也就是下标为Math.floor(arr.length/2)-1,从左至右 从下至上 然后按照大顶堆的形式进行调整,进行"堆化"
  2. 然后此时堆顶元素是最大值,将堆顶元素和末尾元素进行交换,然后继续将剩下的len-1个元素继续进行"堆化"

代码:

var arr = [9, 5, 3, 6, 2]
var len = arr.length

function heapSort(arr) {
    buildHeap(arr);//构造大顶堆
    for (var i = len - 1; i > 0; i--) {
        [arr[0], arr[i]] = [arr[i], arr[0]];
        len--;
        heapify(arr, 0)
    }
}

function heapify(arr, i) {//将当前元素和左右子元素进行比较

    let left = 2 * i + 1,
        right = 2 * i + 2,
        largest = i;

    if (left < len && arr[largest] < arr[left]) {
        largest = left
    }

    if (right < len && arr[largest] < arr[right]) {
        largest = right
    }

    if (largest !== i) {
        [arr[largest], arr[i]] = [arr[i], arr[largest]];
    }
}

function buildHeap(arr) {
    for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {//从第一个非叶子结点开始
        heapify(arr, i, len)
    }
}

heapSort(arr)
console.log(arr);//[ 2, 3, 5, 6, 9 ]

优先级队列

同时通过堆这个数据结构,我们可以构造出另一个常用的数据结构——优先级队列。

我们知道普通的队列是先进先出,优先级队列 则是根据优先级进行处理的,根据具体场景,优先级的标准也不同。

比如:在操作系统的磁盘调度算法,有最短寻道时间优先和先来先服务等,最短寻道时间就是它的优先级。