使用堆在 O(n + klogk) 中获取按排序顺序输出的数组中的最大 k 个元素?

Getting largest k elements in an array outputted in sorted order in O(n + klogk) using heaps?

我试图将算法的运行时间降低到 O(n + klogk),但我似乎做不到。我通过使用最小堆得到 O(n + nlogk)。基本上算法如下:

  1. 构建给定数组的前 k 个元素(arr[0] 到 arr[k-1])的最小堆 MH。 O(k)

  2. 对每个元素,在第k个元素(arr[k]到arr[n-1])之后,与MH的根进行比较。 O((n-k)logk)

  3. 最后,MH有k个最大的元素,MH的根是第k大的元素。调用 extractMin k 次得到 O(klogk)。

这让我得到 O(k + (n-k)Logk + kLogk),等于 O(k + nlogk)。但我需要 O(n + klogk)。

我不知道如何使用最小堆来加快速度。有什么建议么?

使用这种 min-heap 方法的问题是您必须不断地处理整个数组的其余部分,从而为您提供 [=11= 的 n 因子 in-front ].

有一种方法可以减少实际提取k个元素所做的工作,方法是使用divide-and-conquer 类似于快速排序的策略。这会以指数方式减少数组中必须处理的部分。

  1. Select 随机枢轴元素。
  2. 将数组分成比主元大和小的部分,就像在快速排序中一样。假设左边有L,右边有R
  3. 如果 k == L 那么我们就完成了:数组中的前 k 个元素是最小的。
  4. 如果k < L则从1继续,只处理左边的分区。
  5. 如果 k > L 则从 1 继续,使用新值 k' = k - L 处理正确的分区。

如果上面的描述含糊不清(编辑:可能是),这种方法是众所周知的,并且有很多来源(here's one 来自 SO,带有代码)。

假设平均情况下pivot将数组大致平分为两半(这也是理想情况),时间复杂度递归关系由T(m) = T(m/2) + O(m)给出,也就是说上述算法是 O(n).

在此之后,数组的前 k 个元素是无序的,因此只需在 O(k log k) 处对它们进行排序。因此,根据需要,总复杂度为 O(n + k log k)