可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
in C++ would like to sort a lengthy (2^20) vector of reals, obviously sort() does the trick. Having used R before I was used to the nice order() function which yields the permutation that leads to the sorted vector. Probably someone has done this in C++, maybe it's just my weak google-Fu that prevents me from finding it. And yeah, obivously my C++ newbness could stop me from spotting something straightforward.
Example:
x = {24, 55, 22, 1}
then the permutation
perm = {3, 2, 0, 1}
maps the original x to the sorted x in ascending order.
I can probably implement some bubble sort which does not only sort x but performs the same transpositions on the vector {0,1,2,...} and outputs both, but I believe someone must have thought about it and especially have done it efficiently.
Thank you very much, Philipp
回答1:
Edit
Better than before approach without using helper vectors: (source on ideone):
#include <vector> #include <algorithm> #include <iostream> template<class Vals> void sortingPermutation(const Vals& values, std::vector<int>& v){ int size = values.size(); v.clear(); v.reserve(size); for(int i=0; i < size; ++i) v.push_back(i); std::sort(v.begin(), v.end(), [&values](int a, int b) -> bool { return values[a] < values[b]; }); } int main() { std::vector<double> values; values.push_back(24); values.push_back(55); values.push_back(22); values.push_back(1); std::vector<int> permutation; sortingPermutation(values, permutation); typedef std::vector<int>::const_iterator I; for (I p = permutation.begin(); p != permutation.end(); ++p) std::cout << *p << " "; std::cout << "\n"; }
I am using lambda from C++0x, but it can be replaced with simple functor object:
template<class T> struct CmpPairs{ CmpPairs(const std::vector<T> &v): v_(v) {} std::vector<T> v_; bool operator()(int a, int b){ return v_[a] < v_[b]; } }; template<class T> CmpPairs<T> CreateCmpPairs(const std::vector<T> & v) { return CmpPairs<T>(v); } //in sortingPermutation: std::sort(v.begin(), v.end(), CreateCmpPairs(values));
Source of old solution with std::map
: ideone
回答2:
I would say the best way would be to create a vector of ints 0..N and then sort that array with a comparison function that compares the corresponding elements of the vector you're trying to find the sorted permutation of. Something like:
#include <vector> #include <algorithm> template<class T> class sorter { const std::vector<T> &values; public: sorter(const std::vector<T> &v) : values(v) {} bool operator()(int a, int b) { return values[a] < values[b]; } }; template<class T> std::vector<int> order(const std::vector<T> &values) { std::vector<int> rv(values.size()); int idx = 0; for (std::vector<int>::iterator i = rv.begin(); i != rv.end(); i++) *i = idx++; std::sort(rv.begin(), rv.end(), sorter<T>(values)); return rv; }
This minimizes the allocation overhead, as we don't create any large temporary object that we sort and then extract the final permution -- the same vector that is being returned is the temp for sorting.
回答3:
You can use std::sort
to sort the list of pairs {(24, 0), (55, 2), (22, 0), (1, 1)}. It isn't particularly pretty, but I usually do something like this:
#include <vector> #include <algorithm> #include <utility> typedef std::pair<double, int> Pair; struct CmpPair { bool operator()(const Pair& a, const Pair& b) { return a.first < b.first; } }; void sortingPermutation( const std::vector<double>& values, std::vector<int>& permutation) { std::vector<Pair> pairs; for (int i = 0; i < (int)values.size(); i++) pairs.push_back(Pair(values[i], i)); std::sort(pairs.begin(), pairs.end(), CmpPair()); typedef std::vector<Pair>::const_iterator I; for (I p = pairs.begin(); p != pairs.end(); ++p) permutation.push_back(p->second); }
Here is the test:
#include <iostream> int main() { std::vector<double> values; values.push_back(24); values.push_back(55); values.push_back(22); values.push_back(1); std::vector<int> permutation; sortingPermutation(values, permutation); typedef std::vector<int>::const_iterator I; for (I p = permutation.begin(); p != permutation.end(); ++p) std::cout << *p << " "; std::cout << "\n"; }