正如标题所说,我正在寻找一种方法来对矢量进行排序,而无需修改原始矢量。 我的第一个想法当然是在排序之前创建一个向量副本,例如:
std::vector<int> not_in_place_sort(const std::vector<int>& original)
{
auto copy = original;
std::sort(copy.begin(), copy.end());
return copy;
}
但是,使用C ++标准算法(可能是sort
和transform
的组合?)可能有更有效的方法来执行排序?)
答案 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)