使用c++(最好是标准库),我想对一个样本序列进行升序排序,但我也想记住新样本的原始索引。
例如,我有一个集合,或向量,或样本a的矩阵:[5,2,1,4,3]。我想把它们排序为B:[1,2,3,4,5],但我也想记住这些值的原始索引,所以我可以得到另一个集合,它将是:
C:[2,1,4,3,0] -这对应于'B'中每个元素的索引,在原始'A'中。
例如,在Matlab中,你可以这样做:
[a,b]=sort([5, 8, 7])
a = 5 7 8
b = 1 3 2
有谁能想到一个好办法吗?
你可以对std::pair进行排序,而不仅仅是整型——第一个整型是原始数据,第二个整型是原始索引。然后提供一个只对第一个int进行排序的比较器。例子:
Your problem instance: v = [5 7 8]
New problem instance: v_prime = [<5,0>, <8,1>, <7,2>]
使用类似这样的比较器对新问题实例进行排序:
typedef std::pair<int,int> mypair;
bool comparator ( const mypair& l, const mypair& r)
{ return l.first < r.first; }
// forgetting the syntax here but intent is clear enough
在v_prime上使用比较器std::sort的结果应该是:
v_prime = [<5,0>, <7,2>, <8,1>]
您可以通过遍历向量来剥离索引,从每个std::pair中抓取.second。
我的解法使用了余数法。我们可以把需要排序的值放在上面2个字节,而把元素的下标放在下面2个字节:
int myints[] = {32,71,12,45,26,80,53,33};
for (int i = 0; i < 8; i++)
myints[i] = myints[i]*(1 << 16) + i;
然后像往常一样对数组myint进行排序:
std::vector<int> myvector(myints, myints+8);
sort(myvector.begin(), myvector.begin()+8, std::less<int>());
在此之后,您可以通过渣滓访问元素的指数。下面的代码输出按升序排序的值的索引:
for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << (*it)%(1 << 16);
当然,这种技术只适用于原始数组myint中相对较小的值(即可以装入int的前2个字节的值)。但是它还有一个额外的好处,可以区分相同的myint值:它们的下标将按正确的顺序打印。
假设给定向量为
A=[2,4,3]
创建一个新向量
V=[0,1,2] // indicating positions
对V进行排序,而不是比较V中的元素,比较A中对应的元素
//Assume A is a given vector with N elements
vector<int> V(N);
std::iota(V.begin(),V.end(),0); //Initializing
sort( V.begin(),V.end(), [&](int i,int j){return A[i]<A[j];} );
还有另一种方法来解决这个问题,使用地图:
vector<double> v = {...}; // input data
map<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m[*it] = it - v.begin();
这将消除非唯一元素。如果不能接受,使用multimap:
vector<double> v = {...}; // input data
multimap<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m.insert(make_pair(*it, it - v.begin()));
为了输出索引,迭代map或multimap:
for (auto it = m.begin(); it != m.end(); ++it)
cout << it->second << endl;