按顺序查找k个最大元素

时间:2013-01-22 01:14:08

标签: algorithm sorting selection

按顺序查找数组中k个最大元素的最快方法是什么(即从最大元素到第k个最大元素)?

7 个答案:

答案 0 :(得分:11)

一个选项如下:

  1. 使用线性时间selection algorithm,如中位数或中位数,找到第k个最大元素并重新排列元素,使第k个元素前向的所有元素都大于第k个元素。

  2. 使用快速排序算法(如heapsort或quicksort)对第k个前进的所有元素进行排序。

  3. 步骤(1)花费时间O(n),步骤(2)花费时间O(k log k)。总的来说,算法在时间O(n + k log k)内运行,这非常非常快。

    希望这有帮助!

答案 1 :(得分:1)

C ++还提供了partial_sort算法,它解决了选择最小k个元素(已排序)的问题,时间复杂度为O(n log k)。没有提供用于选择最大k个元素的算法,因为这应该通过反转排序谓词来完成。

对于Perl,CPAN提供的模块Sort :: Key :: Top提供了一组函数,用于使用多个排序和自定义键提取过程从列表中选择前n个元素。此外,Statistics :: CaseResampling模块提供了使用quickselect计算分位数的功能。

Python的标准库(自2.4起)包括heapq.nsmallest()和nlargest(),返回排序列表,前者在O(n + k log n)时间内,后者在O(n log k)时间内。 / p>

答案 2 :(得分:1)

基数排序解决方案:

  • 使用基数排序按降序对数组进行排序;
  • 先打印K个元素。

时间复杂度:O(N * L),其中L =最大元素的长度,可以假设L = O(1)。 使用的空间:O(N)用于基数排序。

然而,我认为基数排序具有高昂的开销,使其线性时间复杂度降低了吸引力。

答案 3 :(得分:1)

1)在O(n)中构建一个最大堆树 2)使用Extract Max k次从最大堆O(klogn)获得k个最大元素

时间复杂度:O(n + klogn)

使用STL的C ++实现如下:

#include <iostream>
#include<bits/stdc++.h>

using namespace std;

int main() {

  int arr[] = {4,3,7,12,23,1,8,5,9,2}; 

  //Lets extract 3 maximum elements
    int k = 3;  

    //First convert the array to a vector to use STL
    vector<int> vec;
    for(int i=0;i<10;i++){
        vec.push_back(arr[i]);
    }

  //Build heap in O(n)
  make_heap(vec.begin(), vec.end());

  //Extract max k times
  for(int i=0;i<k;i++){
      cout<<vec.front()<<" ";
      pop_heap(vec.begin(),vec.end());
      vec.pop_back();
  }
  return 0;
}

答案 4 :(得分:0)

@ templatetypedef的解决方案可能是最快的解决方案,假设您可以修改或复制输入。

或者,您可以使用堆或BST(C ++中的set)在给定时刻存储k个最大元素,然后逐个读取数组元素。虽然这是O(n lg k),但它不会修改输入,只使用O(k)附加内存。它也适用于流(当你不知道从头开始的所有数据时)。

答案 5 :(得分:0)

这是一个O(N + k lg k)复杂度的解决方案。

int[] kLargest_Dremio(int[] A, int k) {
  int[] result = new int[k];
  shouldGetIndex = true;
  int q = AreIndicesValid(0, A.Length - 1) ? RandomizedSelet(0, A.Length-1,
    A.Length-k+1) : -1;
  Array.Copy(A, q, result, 0, k);
  Array.Sort(result, (a, b) => { return a>b; });
  return result;
} 

AreIndicesValidRandomizedSeletthis github source file中定义。

答案 6 :(得分:0)

有关性能和受限资源的问题。

为前3个值创建一个值类。使用这种累加器减少并行流。根据上下文(内存,电源)限制并行度。

class BronzeSilverGold {
    int[] values = new int[] {Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE};

    // For reduction
    void add(int x) {
        ...
    }

     // For combining two results of two threads.
    void merge(BronzeSilverGold other) {
        ...
    }
}

必须在您的星座图中限制并行性,因此请在以下位置指定N_THREADS:

try {
    ForkJoinPool threadPool = new ForkJoinPool(N_THREADS);
    threadPool.submit(() -> {
        BronzeSilverGold result = IntStream.of(...).parallel().collect(
            BronzeSilverGold::new,
            (bsg, n) -> BronzeSilverGold::add,
            (bsg1, bsg2) -> bsg1.merge(bsg2));
        ...
    });
} catch (InterruptedException | ExecutionException e) {
    prrtl();
}