C++ 如何在保持顺序的同时有效地将列表插入到已排序的向量中?

C++ 如何在保持顺序的同时有效地将列表插入到已排序的向量中?,c++,concatenation,stl-algorithm,C++,Concatenation,Stl Algorithm,我想将STL列表的内容插入到现有的向量中,这样在插入之后向量仍然会被排序 下面是我正在努力有效地执行的代码。虽然它会起作用,但我相信应该有一种更好的连接方式 向量V在描述合并操作之前确实有一些元素 Size(V) > Size(L) 如果这些信息还有帮助的话 void merge(std::list<int>& L, std::vector<int>& V) { for (auto& x : L) V.push_back(x);

我想将STL列表的内容插入到现有的向量中,这样在插入之后向量仍然会被排序

下面是我正在努力有效地执行的代码。虽然它会起作用,但我相信应该有一种更好的连接方式

向量V在描述合并操作之前确实有一些元素

Size(V) > Size(L)
如果这些信息还有帮助的话

void merge(std::list<int>& L, std::vector<int>& V) {
    for (auto& x : L) V.push_back(x);
    std::sort(V.begin(), V.end());
}

代码需要用C++14编写。

使用vector::insert可以很容易地做到这一点,尽管我不认为该实现可以有效地获得两个双向迭代器之间的距离,因此您可能希望保留空间以避免不必要的向量大小调整。至少从C++11开始,list::size似乎必须是常数时间,所以如果您至少在该版本上,您只需在前面预留足够的空间即可。否则,因为您知道V大于L,所以在插入之前,只需将V的容量增加一倍:


使用vector::insert可以很容易地做到这一点,尽管我不认为该实现可以有效地获得两个双向迭代器之间的距离,因此您可能希望保留空间以避免不必要的向量大小调整。至少从C++11开始,list::size似乎必须是常数时间,所以如果您至少在该版本上,您只需在前面预留足够的空间即可。否则,因为您知道V大于L,所以在插入之前,只需将V的容量增加一倍:


假设向量已排序并将保持排序,则:

void merge(std::list<int> const& L, std::vector<int>& V) {
  auto old_end = V.size();
  V.insert( V.end(), L.begin(), L.end() );
  std::sort( V.begin()+old_end, V.end() );
  std::inplace_merge( V.begin(), V.begin()+old_end, V.end() );
}
可能是相对最优的。请注意,inplace_merge可能会进行分配,因此这可能不像人们希望的那样最佳

.insert保证保留空间,最多只能重新分配一次

接下来,我们只对列表中的元素进行排序,然后进行就地合并,将其与向量前面先前排序的元素合并


我还将该列表设置为常量,因为我们不会对其进行修改。

假设您的向量已排序并将保持排序,则:

void merge(std::list<int> const& L, std::vector<int>& V) {
  auto old_end = V.size();
  V.insert( V.end(), L.begin(), L.end() );
  std::sort( V.begin()+old_end, V.end() );
  std::inplace_merge( V.begin(), V.begin()+old_end, V.end() );
}
可能是相对最优的。请注意,inplace_merge可能会进行分配,因此这可能不像人们希望的那样最佳

.insert保证保留空间,最多只能重新分配一次

接下来,我们只对列表中的元素进行排序,然后进行就地合并,将其与向量前面先前排序的元素合并


我还将列表设置为常量,因为我们不会修改它。

V.insertV.end,L.begin,L.end;请看。我们知道要连接的列表L的大小,这对任何情况都有帮助吗?我相信在这种情况下,std::vector::insert会丢失这些信息,因为std::distance对于列表的迭代器来说不是常数时间。也许你可以叫V.reserveV.size+L.size;弗朗索瓦·安德烈给出了一个正确的答案,这是最佳的解决方案。在手动调用push_back的情况下,您可以多次重新分配向量,基于范围的插入将确保只发生一次。向量排序的事实很重要。V.insertV.end,L.begin,L.end;请看。我们知道要连接的列表L的大小,这对任何情况都有帮助吗?我相信在这种情况下,std::vector::insert会丢失这些信息,因为std::distance对于列表的迭代器来说不是常数时间。也许你可以叫V.reserveV.size+L.size;弗朗索瓦·安德烈给出了一个正确的答案,这是最佳的解决方案。在手动调用push_back的情况下,您可以多次重新分配向量,基于范围的插入将确保只发生一次。向量已排序这一事实很重要。inplace_merge可能会分配,因此这可能值得进行基准测试。我更喜欢这一个!如果insert保证最多分配一次,这是否意味着在实际工作之前,需要在L上进行两次迭代,以获得要插入的项目的大小?@MarkB是的,这是真的。但是除非列表很大,比如缓存破坏很大,第一次通过缓存元素,第二次将从缓存中读取。所以没有巨大的损失。理论上,先使用manual.reserve.size,然后再将迭代器转换为输入迭代器!可能更快,或者是一个手动循环,编译器在其中计算出push_back不需要检查边界。我们需要这个方法。我认为最理想的方法是将列表复制到一个临时向量中,对其进行排序,然后仔细地将其合并到第一个向量中!如果insert保证最多分配一次,这是否意味着在实际工作之前,需要在L上进行两次迭代,以获得要插入的项目的大小?@MarkB是的,这是真的。但是除非列表很大,比如缓存破坏很大,第一次通过缓存元素,第二次将从缓存中读取。所以没有巨大的损失。理论上,先使用manual.reserve.size,然后再将迭代器转换为输入迭代器!可以更快,也可以是编译器工作的手动循环
推回不需要检查边界,我们需要这种方法。我认为最理想的方法是将列表复制到一个临时向量中,排序,然后小心地将其合并到第一个向量中。虽然OP接受了你的答案,但我改变了他的问题,注意到他如何解释他真正想要的是该向量的排序版本。仅供参考。该代码假设列表的顺序相同,且元素数大于原始向量,但原始问题已说明,……因此向量在插入后仍然排序,但这并不保证。下面的解决方案保证了这一点,并且在不使用原始向量的情况下是有效的。当问题被编辑以将需求从串联更改为添加元素,同时保持容器排序时,我错过了。显然,另一个答案更好地解决了新问题,因此我将删除此编辑:无法删除接受的答案。虽然OP接受了你的答案,但我修改了他的问题,注意到他如何解释他真正想要的是向量的排序版本。仅供参考。该代码假设列表的顺序相同,且元素数大于原始向量,但原始问题已说明,……因此向量在插入后仍然排序,但这并不保证。下面的解决方案保证了这一点,并且在不使用原始向量的情况下是有效的。当问题被编辑以将需求从串联更改为添加元素,同时保持容器排序时,我错过了。显然,另一个答案更好地解决了新问题,因此我将删除此编辑:无法删除已接受的答案。