📌  相关文章
📜  Javascript程序以原始顺序查找数组的k个最大元素(1)

📅  最后修改于: 2023-12-03 15:16:18.396000             🧑  作者: Mango

Javascript程序以原始顺序查找数组的k个最大元素

在很多应用场景下,我们需要找到一个数组中的前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个最大元素的任务,代码也已经实现完整。在日常开发中,对数据的查找和筛选往往是十分重要的,因此我们需要合理应用合适的算法,提高代码的效率。