考虑std::vector
v
个N
元素,并考虑n
第一个元素已经使用n < N
进行排序,其中(N-n)/N
非常小:
是否有一种聪明的方法使用STL算法来比使用完整的std::sort(std::begin(v), std::end(v))
更快地对此向量进行排序?
编辑:澄清:(N-n)未排序的元素应插入已排序的n个第一个元素中的正确位置。
EDIT2:奖金问题:以及如何找到n? (对应于第一个未排序的元素)
答案 0 :(得分:23)
仅对其他范围排序,然后使用std::merge。
答案 1 :(得分:20)
void foo( std::vector<int> & tab, int n ) {
std::sort( begin(tab)+n, end(tab));
std::inplace_merge(begin(tab), begin(tab)+n, end(tab));
}
用于编辑2
auto it = std::adjacent_find(begin(tab), end(tab), std::greater<int>() );
if (it!=end(tab)) {
it++;
std::sort( it, end(tab));
std::inplace_merge(begin(tab), it, end(tab));
}
答案 2 :(得分:8)
最佳解决方案是独立地对尾部进行排序,然后执行就地合并,如此处所述
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.22.5750
该算法非常复杂,通常被认为“不值得努力”。
当然,使用C ++,您可以使用现成的std::inplace_merge
。但是,该算法的名称极具误导性。首先,不能保证std::inplace_merge
实际上就地工作。当它实际就位时,并不能保证它不会被实现为完整的排序。在实践中,它归结为尝试它,看它是否足以满足您的目的。
但是如果你真的想要就地制作并且正式比完全排序更有效,那么你将不得不手动实现它。 STL可能有助于一些实用程序算法,但它没有提供任何“只需几次调用标准函数”的可靠解决方案。
答案 3 :(得分:4)
在N - n
个最后元素上使用插入排序:
template <typename IT>
void mysort(IT begin, IT end) {
for (IT it = std::is_sorted_until(begin, end); it != end; ++it) {
IT insertPos = std::lower_bound(begin, it, *it);
IT endRotate = it;
std::rotate(insertPos, it, ++endRotate);
}
}
答案 4 :(得分:3)
Timsort排序算法是由Pythonista Tim Peters开发的混合算法。它可以最佳地利用数组内部已经排序的子区域 ,包括在开头。虽然您可以找到更快的算法,但如果您确定特别是第一个 n元素已经排序,则此算法应该对所涉及的整体类问题有用。维基百科将其描述为:
该算法查找已经排序的数据的子集,并使用该知识更有效地对其余部分进行排序。
用蒂姆彼得斯自己的话说,
它有很多超自然的表现 各种部分有序的数组(需要少于lg(N!)的比较,和 只有N-1),但速度与Python之前高度调整的样本一样快 混合随机阵列。
详细说明in this undated text document by Tim Peters。示例是在Python中,但即使对于不熟悉其语法的人来说,Python也应该是可读的。
答案 5 :(得分:1)
使用std :: partition_point(或is_sorted_until)查找n。然后,如果n-m很小,则进行插入排序(线性搜索+ std :: rotate)。
答案 6 :(得分:1)
我认为你的问题有两个目的:
考虑到这些目标,我强烈建议不要进行这种特定的优化,除非您确定这项工作是值得的。 据我所知,std :: sort()实现了快速排序算法,它几乎与预分类输入一样快,以确定输入是否/如何排序。
您可以尝试将数据结构更改为已排序/优先排序的队列,而不是插入std :: sort。