调用std :: nth_element之后第n个元素之前的元素顺序

时间:2017-10-12 01:15:56

标签: c++

我感兴趣的是找到一个等于中位数的向量中第一个(最左边)元素的最有效方法。找到中位数很简单:

std::nth_element(first, middle, last);
auto median = *middle;

但是如果输入类似于{2,2,2,2,1},那么在调用std :: nth_element之后,中间元素之前会有2s。我是否必须搜索中间左侧的所有值?还是保证2s都会相邻?

另一种问这个问题的方法是,如上所述调用std :: nth_element后是否可以{2,1,2,2},或保证{1,2,2,2,2}?在后一种情况下,我可以从中间向左搜索。在前者中,我必须从第一个到中间搜索,效率较低。从实证检验来看,后一种情况似乎成立。想知道是否有人有明确答案或者我错过了一些角落案件。

2 个答案:

答案 0 :(得分:1)

The documentation only guarantees

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

请注意, no 保证第n个元素之前或之后的元素以任何特定顺序出现,只要之前的元素小于或等于它(并且通过扩展,到期)它的本质是第n个元素,它之后的元素大于或等于它;); {2, 1, 2, 2, 2}{1, 2, 2, 2, 2}都是完全合法的排序。

答案 1 :(得分:0)

第n个元素不保证在第n个元素之前的元素顺序。

如果没有与第n个相等的成员元素,或者只是排序的小名单,可能很难推动,所以这可能就是你所看到的。

了解如何实现第n个元素可能有所帮助:这只是一个例子。

实现第n个元素的一种方法是将中位数设为5.取你的集合并将其分成5个团块。对每个团块进行排序(O(1)* O(n))。现在重复5个元素块的中位数,找到它的真实中位数(使用第n个元素)。

最终,您将获得接近中间的单个元素(介于0.3和0.7之间),并且需要线性时间。 (

对序列进行分区(线性时间),现在您的序列中的元素按顺序排列(通过计数)。

如果它是第n个元素,那么你正在寻找第k个和第k个

当您使用线性时间算法搜索指数较小的区域时,整个算法都是线性时间。

请注意,这可能会严重混淆元素的顺序;没有保证相等的元素是相邻的。

有关详细信息,请参阅https://en.m.wikipedia.org/wiki/Median_of_medians