堆这个数据结构在面试中经常被面试官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]
构建堆
- 我们可以先把数组以二叉树的形式写出来,然后按照大顶堆的形式将二叉树结构进行改造,从第一个非叶子节点开始,也就是下标为Math.floor(arr.length/2)-1,从左至右 从下至上 然后按照大顶堆的形式进行调整,进行"堆化"
- 然后此时堆顶元素是最大值,将堆顶元素和末尾元素进行交换,然后继续将剩下的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 ]
优先级队列
同时通过堆这个数据结构,我们可以构造出另一个常用的数据结构——优先级队列。
我们知道普通的队列是先进先出,优先级队列 则是根据优先级进行处理的,根据具体场景,优先级的标准也不同。
比如:在操作系统的磁盘调度算法,有最短寻道时间优先和先来先服务等,最短寻道时间就是它的优先级。