C++ 是否有插入然后排序的替代方法
如果我有C++ 是否有插入然后排序的替代方法,c++,sorting,insert,merge,stl-algorithm,C++,Sorting,Insert,Merge,Stl Algorithm,如果我有vector foo和vector bar两个都已排序,并且我想将它们合并到foo中,以便对最终结果进行排序,那么标准是否为我提供了这样做的方法 显然,我能做到: foo.insert(foo.end(), bar.begin(), bar.end()); sort(foo.begin(), foo.end()); 但我希望有一个一步算法来完成这一点。要详细说明Mat的评论,您的代码可以使用std::merge: std::vector<int> result; std::
vector foo
和vector bar
两个都已排序,并且我想将它们合并到foo
中,以便对最终结果进行排序,那么标准是否为我提供了这样做的方法
显然,我能做到:
foo.insert(foo.end(), bar.begin(), bar.end());
sort(foo.begin(), foo.end());
但我希望有一个一步算法来完成这一点。要详细说明Mat的评论,您的代码可以使用
std::merge
:
std::vector<int> result;
std::merge(
foo.begin(), foo.end(),
bar.begin(), bar.end(),
std::back_inserter(result));
foo = result; // if desired
std::向量结果;
合并(
foo.begin(),foo.end(),
bar.begin(),bar.end(),
标准:背向插入器(结果);
foo=结果;//如果需要
使用它可能比使用std::sort
更快。如果有额外的可用内存,则它具有线性复杂度,否则它会返回到NlogN
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
std::inplace_merge(foo.begin(), middle, foo.end());
如果你需要这种合并,为什么不自己做一个呢
template <class Vector>
void insert_sorted(Vector& where, Vector& what)
{
typename Container::iterator src = what.begin();
typename Container::iterator src_end = what.end();
size_t index = 0;
while(src != src_end)
{
if(*src < where[index])
{
where.insert(where.begin() + index, *src);
++src;
}
++index;
}
}
实时样本:。所以在查看了所有标准算法后,我可以确认,在搜索标准算法时,除了插入和排序没有其他选择。我注意到,所有复制算法都使用输入迭代器和输出迭代器。唯一使用输入输出迭代器的时间是在单个范围上操作时。(例如,
sort
使用输入输出迭代器,但任何copy
都使用输入迭代器和输出迭代器。)
我想举例说明我的观点。因此,让我们举一个带有输入输出迭代器的插入合并算法的示例:
template <class BidirectionalIterator, class InputIterator>
void func(BidirectionalIterator first1, BidirectionalIterator last1, InputIterator first2, InputIterator last2){
bool is1Empty = first1 == last1;
bool is2Empty = first2 == last2;
BidirectionalIterator end = next(last1, distance(first2, last2));
if (!is1Empty){
--last1;
}
if (!is2Empty){
--last2;
}
while (!is1Empty || !is2Empty){
--end;
if (!is1Empty){
if (!is2Empty && *last2 > *last1){
*end = *last2;
if (last2 == first2){
is2Empty = true;
}else{
--last2;
}
}else{
*end = *last1;
if (last1 == first1){
is1Empty = true;
}
else{
--last1;
}
}
}else{
*end = *last2;
if (last2 == first2){
is2Empty = true;
}
else{
--last2;
}
}
}
}
请注意,它利用了合并两个排序范围的知识,因此速度与func
相当:
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
inplace_merge(foo.begin(), middle, foo.end());
唯一实际的“一步算法”是将这个高炉的答案滚动到一个函数中,你可以通过传递要合并的容器来调用该函数。@Mat:这会产生某种合并排序吗?合并到一个临时值,然后交换。更糟的是什么意思?时间复杂性——我不这么认为。内存开销-是的,可能是。交换是固定时间的,而且速度非常快。(如果您试图保存一行代码,…)@JonathanMee是否是您的一行代码的候选项?这是一个比我在问题中已经建议的更糟糕的解决方案,因为它需要创建另一个临时的
向量。此外,它不能满足“一步算法完成此任务”的要求。可以通过为结果
预先分配存储来提高效率。它具有较低的复杂性,尽管不是一步完成的。最后一部分可能是一个动作,可能使它成为你能为此设计的最快算法。@JonathanMee在我的测试程序std:merge
中保持foo
和bar
不变,结果
充满了合并列表,就像上面说的那样。@Tobimnamobi你是对的,我的错误,我以为您的输出是back\u inserter(foo)
@Lingxi:此算法试图分配一些临时缓冲内存以允许线性复杂度,如果它不能,它将使用一个效率较低的(NlogN)算法。我投了赞成票,但让我们明确一点,std::inplace\u merge()
与TobiMcNamobi的代码做了完全相同的事情(假设有足够的内存可用),因此如果OP对该解决方案不满意,他真的应该对该解决方案同样不满意。@j_random_hacker那不是真的,TobiMcNamobi的解决方案不起作用:@JonathanMee:我们知道insert()
使foo.end()无效
迭代器,不考虑容器的容量。将其与评估问题的顺序结合起来,这使得单行程序的概念非常粗略。@JonathanMee:不用担心:)出于这个原因,我认为inplace\u merge
确实是更方便的选择,而且我已经反复强调了这样一个事实,即在内部它只会做TobiMcNamobi的代码所做的事情,因此,当涉及到std算法时,编写自己的代码通常是有风险的。虽然这个特别的问题很容易,所以我可以考虑,但我不会承认这样做。你的算法有缺陷。如果中的最后一个元素(如果有)小于中的第一个元素,当foo
小于bar
时,@MateuszGrzejek断言会怎样。我同意自己写,但这不起作用。@MateuszGrzejek如果您可以从注释中对其进行解释,这可能会更有效:for(Container::iterator toIterator=where.begin(),fromtiterator=what.begin();fromtiterator!=what.end();+fromtiterator){while(toIterator!=where.end()&*toIterator<*fromtiterator)++toIterator;toIterator=where.insert(toIterator,*fromtiterator);}
这是一个最小的解决方案,说明了可能的概念。是的,需要进行调整-但是,请注意,如果我们能够对参数的内容做出一些保证,则检查所有可能的情况(空where
,空what
,等等)可能没有必要。现在,由OP根据他的需要来调整。
template <class BidirectionalIterator, class InputIterator>
void func(BidirectionalIterator first1, BidirectionalIterator last1, InputIterator first2, InputIterator last2){
bool is1Empty = first1 == last1;
bool is2Empty = first2 == last2;
BidirectionalIterator end = next(last1, distance(first2, last2));
if (!is1Empty){
--last1;
}
if (!is2Empty){
--last2;
}
while (!is1Empty || !is2Empty){
--end;
if (!is1Empty){
if (!is2Empty && *last2 > *last1){
*end = *last2;
if (last2 == first2){
is2Empty = true;
}else{
--last2;
}
}else{
*end = *last1;
if (last1 == first1){
is1Empty = true;
}
else{
--last1;
}
}
}else{
*end = *last2;
if (last2 == first2){
is2Empty = true;
}
else{
--last2;
}
}
}
}
foo.resize(foo.size() + bar.size());
func(foo.begin(), next(foo.begin(), foo.size() - bar.size()), bar.begin(), bar.end());
auto middle = foo.insert(foo.end(), bar.begin(), bar.end());
inplace_merge(foo.begin(), middle, foo.end());