在C ++中从容器中选择k个最小元素的“最佳”(惯用)方法

时间:2012-03-14 15:01:11

标签: c++ algorithm stl stl-algorithm

我经常发现自己遇到这个问题:给定一个序列,找到k-最小的元素。问题并不那么难,但我正在寻找的是一种“惯用”的方式,这是安全的(几个错误的地方)并且很好地沟通意图。所以最终做的是对序列进行排序,然后取第一个k元素:

std::sort(container.begin(),container.end());
std::vector<T> k_smallest(container.begin(),container.begin() + k);

在我看来这既安全又易于理解,但这里的复杂性是nlogn + k,而不仅仅是n。 你们是如何做到这一点的,是否有一种自觉的方式(使用一些不起眼的功能)可以提供最佳的复杂性而无需重新实现轮子

3 个答案:

答案 0 :(得分:16)

std::nth_element() - 平均线性复杂度。

  

nth_element是一种重新排列元素的部分排序算法   [first,last]这样:

     
      
  • 如果[first,last]已排序,则第n个指向的元素将更改为该位置中出现的任何元素。
  •   
  • 这个新的第n个元素之前的所有元素都小于或等于新的第n个元素之后的元素。
  •   

答案 1 :(得分:7)

您可能需要查看partial_sort()

它很容易理解,不需要额外的工作,并且如果你只关心第k个元素,那么预期会更好[或者至少不会更差] sort()

为获得最佳性能 - 您可能希望使用selection algorithm,但需要更多工作。

答案 2 :(得分:0)

第一个算法:

<强>步骤:

  • 使用Selection algorithm查找第k个元素。
  • 选择它作为一个支点并执行分区(来自quick sort算法),导致将最小的k个元素留在枢轴上。

<强>复杂度: O(n)最坏情况

第二算法:

<强>步骤:

  • 使用make_heap从数组元素中创建堆。
  • 执行以下k次:
    • 阅读第一个元素。
    • 使用pop_heap
    • 弹出它

您可以使用priorty queue的方法(c'tortoppop)来了解后面的算法。

<强>复杂度: O(n + k * log(n))最坏情况