如果您真的是说输出顺序无关紧要,那么您需要std::nth_element
,而不是std::partial_sort
,因为它通常会更快一些。请注意,std::nth_element
将第 n个元素放在正确的位置,因此您可以执行以下操作,这是 100% 的标准算法调用(警告:没有很好地测试;fencepost 错误可能性比比皆是):
template<typename RandomIterator, typename Compare>
void best_n(RandomIterator first,
RandomIterator nth,
RandomIterator limit,
Compare cmp) {
using ref = typename std::iterator_traits<RandomIterator>::reference;
std::nth_element(first, nth, limit, cmp);
auto p = std::partition(first, nth, [&](ref a){return cmp(a, *nth);});
auto q = std::partition(nth + 1, limit, [&](ref a){return !cmp(*nth, a);});
std::random_shuffle(p, q); // See note
}
该函数采用三个迭代器,例如nth_element
,其中nth
是第 n个元素的迭代器,这意味着它是begin() + (n - 1))
。
编辑:请注意,这与大多数 STL 算法不同,因为它实际上是一个包含范围。特别是 UB if nth == limit
,因为它必须*nth
是有效的。此外,没有办法请求best 0
元素,就像没有办法请求第 0个元素一样std::nth_element
。您可能更喜欢使用不同的界面;随意这样做。
或者你可以这样称呼它,在要求之后0 < k <= n
:
best_n(container.begin(), container.begin()+(k-1), container.end(), cmp);
它首先用于nth_element
将“最佳”k
元素放在 position0..k-1
中,以保证第 k个元素(或其中一个)位于 position k-1
。然后它重新划分 position 前面的元素k-1
,使相等的元素位于末尾,并重新划分 position 后面的元素k-1
,使相等的元素位于开头。最后,它打乱相等的元素。
nth_element
是O(n)
;这两个partition
操作的总和为O(n)
; 并且random_shuffle
是O(r)
其中r
是混洗的相等元素的数量。我认为所有的总结都是O(n)
如此,它具有最佳的可扩展性,但它可能是也可能不是最快的解决方案。
注意:您应该使用std::shuffle
而不是std::random_shuffle
,将统一随机数生成器传递给best_n
。但是我懒得写所有的样板来做这件事并测试它。对不起。