📅  最后修改于: 2023-12-03 15:16:18.396000             🧑  作者: Mango
在很多应用场景下,我们需要找到一个数组中的前k个最大元素。常规思路是对数组进行排序,然后取前k个元素。但是这种方法有一个很大的缺陷,就是不管是快速排序、归并排序还是堆排序,时间复杂度都是至少 $O(n\log n)$ 的,因此对于大规模的数组来说,计算量会相当可观。
那么有没有更好的解决方案呢?答案是肯定的。我们可以使用一种名为 “堆” 的数据结构,将时间复杂度降为 $O(n\log k)$。本文将介绍如何使用Javascript程序以原始顺序查找数组的k个最大元素。
首先,我们需要了解什么是堆。堆是一种树形数据结构,其中每个节点都有一个关键字,通常是数值,且对于任何满足 $i>1$ 的节点 $i$ ,都会有 $parent(i)\le{i}$ 。这里的 $parent(i)$ 指的是节点 $i$ 的父节点。这种关系可以形成类似完全二叉树的形式,但是左右儿子之间的大小关系不一定。我们将堆分为”最大堆“和”最小堆“,最大堆的每个节点都大于或等于它的两个子节点,最小堆则是每个节点小于或等于它的两个子节点。
在本例中,我们将使用最大堆(MaxHeap),因为我们要找的是数组的前k个最大元素。
接下来,我们将实现一个MaxHeap类,它将包含以下方法:
constructor()
: 构造函数,用于创建堆insert(item)
: 向堆中插入元素pop():
从堆中取出最大元素peek():
查看堆中最大元素,但不将其从堆中删除size():
查看堆中元素的数量class MaxHeap {
constructor() {
this.heap = [];
this.heap[0] = Number.MAX_SAFE_INTEGER;
}
insert(item) {
this.heap.push(item);
let i = this.heap.length - 1;
while (this.heap[i] > this.heap[Math.floor(i / 2)]) {
[this.heap[i], this.heap[Math.floor(i / 2)]] = [this.heap[Math.floor(i / 2)], this.heap[i]];
i = Math.floor(i / 2);
}
}
pop() {
const max = this.heap[1];
this.heap[1] = this.heap[this.heap.length - 1];
this.heap.pop();
let i = 1;
while (true) {
let maxIndex = i;
if (2 * i < this.heap.length && this.heap[2 * i] > this.heap[maxIndex]) {
maxIndex = 2 * i;
}
if (2 * i + 1 < this.heap.length && this.heap[2 * i + 1] > this.heap[maxIndex]) {
maxIndex = 2 * i + 1;
}
if (maxIndex === i) break;
[this.heap[i], this.heap[maxIndex]] = [this.heap[maxIndex], this.heap[i]];
i = maxIndex;
}
return max;
}
peek() {
return this.heap[1];
}
size() {
return this.heap.length - 1;
}
}
从上面的代码中,我们可以看到MaxHeap类的实现。其中,“向堆中插入元素”的方法使用了插入排序的思想,从新插入的元素开始,与上一个节点比较大小,如果大于上一个节点,就和上一个节点交换位置,直到满足最大堆的结构为止。至于“从堆中取出最大元素”的方法,则是将最大值与最后一个节点交换位置,然后删除该节点,接着再将堆最大堆的结构重新调整。 最后,我们来实现查找数组的k个最大元素的函数。该函数接受一个数组和k作为参数,然后使用MaxHeap类来实现查询。代码如下:
function findKMaxElements(arr, k) {
const maxHeap = new MaxHeap();
for (let i = 0; i < arr.length; i++) {
maxHeap.insert(arr[i]);
if (maxHeap.size() > k) {
maxHeap.pop();
}
}
const res = [];
while (maxHeap.size() > 0) {
res.push(maxHeap.pop());
}
return res.reverse();
}
由于查找的是k个最大元素,所以我们首先用MaxHeap类将前k个元素放到堆中,然后依次将数组中后面的每个元素插入到堆中,如果堆的元素超过了k个,那么就将堆中最大值弹出。最后,堆中剩下的元素就是数组中的前k个最大元素,所以我们将元素逆序输出即可。
到这里,我们就完成了Javascript程序以原始顺序查找数组的k个最大元素的任务,代码也已经实现完整。在日常开发中,对数据的查找和筛选往往是十分重要的,因此我们需要合理应用合适的算法,提高代码的效率。