对矢量进行排序的最佳方法是什么,使原始矢量保持不变?

时间:2017-11-28 17:00:38

标签: c++ sorting stl

正如标题所说,我正在寻找一种方法来对矢量进行排序,而无需修改原始矢量。 我的第一个想法当然是在排序之前创建一个向量副本,例如:

std::vector<int> not_in_place_sort(const std::vector<int>& original)
{
   auto copy = original;
   std::sort(copy.begin(), copy.end());
   return copy;
}

但是,使用C ++标准算法(可能是sorttransform的组合?)可能有更有效的方法来执行排序?)

6 个答案:

答案 0 :(得分:6)

这是我的最爱。对索引进行排序,而不是对原始数组/向量本身进行排序。

#include <algorithm>

int main() {

    int intarray[4] = { 2, 7, 3, 4 };//Array of values
    //or you can have vector of values as below
    //std::vector<int> intvec = { 2, 7, 3, 4 };//Vector of values
    int indexofarray[4] = { 0, 1, 2, 3 };//Array indices

    std::sort(indexofarray, indexofarray + 4, [intarray](int index_left, int index_right) { return intarray[index_left] < intarray[index_right]; });//Ascending order.
    //have intvec in place of intarray for vector.


}

在此之后,indexofarray[]元素将为0, 2, 3, 1,而intarray[]则不会更改。

答案 1 :(得分:2)

根据注释中的建议,通过值std::vector<int> original传递函数参数:

#include <iostream>
#include <vector>
#include <algorithm>

std::vector<int> not_in_place_sort(std::vector<int> original) {
    std::sort(original.begin(), original.end());
    return original;
}

int main() {
    std::vector<int> v = { 8, 6, 7, 2, 3, 4, 1, 5, 9 };
    std::vector<int> v2 = not_in_place_sort(v); // pass the vector by value
    std::cout << "v1: " << '\n';
    for (auto el : v) {
        std::cout << el << ' ';
    }
    std::cout << "\nv2: " << '\n';
    for (auto el : v2) {
        std::cout << el << ' ';
    }
}

这将对原始矢量的副本进行排序,保留原始矢量。 如下所述,这可能会限制某些优化,例如RVO,但会在return语句中调用vector's move constructor

答案 2 :(得分:2)

对于您对代理排序(排序索引列表)感兴趣的情况,您可能希望实现更灵活的算法,该算法允许您处理不支持随机访问的容器(例如#include <algorithm> #include <iostream> #include <list> #include <numeric> #include <vector> template <typename Container> auto sorted_indices(const Container& c) { std::vector<typename Container::size_type> indices(c.size()); std::iota(indices.begin(), indices.end(), 0); std::sort(indices.begin(), indices.end(), [&c](auto lhs, auto rhs) { return (*(std::next(c.begin(), lhs)) < *(std::next(c.begin(), rhs))); }); return indices; } template <typename Container, typename Indices> auto display_sorted(const Container& c, const Indices& indices) { std::cout << "sorted: "; for (auto&& index : indices) { std::cout << *(std::next(c.begin(), index)) << " "; } std::cout << std::endl; } template <typename Container> auto display_sorted(const Container& c) { return display_sorted(c, sorted_indices(c)); } template <typename Container> auto display(const Container& c) { std::cout << "as provided: "; for (auto&& ci : c) std::cout << ci << " "; std::cout << std::endl; } int main() { // random access const std::vector<int> a{9, 5, 2, 3, 1, 6, 4}; display(a); display_sorted(a); display(a); std::cout << "---\n"; // no random access const std::list<int> b{9, 5, 2, 3, 1, 6, 4}; display(b); display_sorted(b); display(b); } )。例如:

$ clang++ example.cpp -std=c++17 -Wall -Wextra
$ ./a.out
as provided: 9 5 2 3 1 6 4 
sorted: 1 2 3 4 5 6 9 
as provided: 9 5 2 3 1 6 4 
---
as provided: 9 5 2 3 1 6 4 
sorted: 1 2 3 4 5 6 9 
as provided: 9 5 2 3 1 6 4 

示例运行:

std::vector

正如您所料,依赖代理排序可能会产生重要的性能影响。例如:每次要按顺序遍历时,都可能会导致缓存未命中。此外,遍历将与用于随机访问的基础容器具有相同的复杂性:在std::next(v.begin(), n)的情况下,O(1)std::list,但在std::next(l.begin(), n)的情况下,O(n)<com.dlazaro66.qrcodereaderview.QRCodeReaderView android:id="@+id/qrdecoderview" android:layout_width="match_parent" android:layout_height="match_parent" />

答案 3 :(得分:1)

对于整体而言,如果您正在对索引进行排序或制作副本,那么它并没有太大的区别。整理副本;数据仍然需要初始化,在索引的情况下,这将涉及循环分配值而不是更快的memcpy例程;所以可能会变慢;此外,你将更多地跳过内存;所以现在缓存不能很好地完成它的工作。

对于较大的对象,我不对索引进行排序,而是使用指针向量。与复制对象本身相比,指针的副本便宜;容器仍然很明显,因为它们包含对象的指针;并且排序没有尝试引用另一个向量。

答案 4 :(得分:0)

使用partial_sort_copy。这是一个示例:

vector<int> v{9,8,6,7,4,5,2,0,3,1};
vector<int> v_sorted(v.size());
partial_sort_copy(begin(v), end(v), begin(v_sorted), end(v_sorted));

现在,v保持不变,但v_sorted包含{0,1,2,3,4,5,6,7,8,9}。

答案 5 :(得分:0)

您可以创建另一个向量来存储索引。这是代码:

@Dependent

来源:根据Tyrer的回答(https://stackoverflow.com/a/47537314)进行了一些修改