根据索引向量重新排序向量 - 更新
Posted
技术标签:
【中文标题】根据索引向量重新排序向量 - 更新【英文标题】:Reorder vector according to a vector of indices - update 【发布时间】:2014-03-06 08:15:12 【问题描述】:这是对previous question about reordering in place 的更新。关于索引向量存在一些混淆。调用要重新排序的向量 vA,以及索引向量 vI,然后 vA 应按此顺序重新排序,vA[vI[0]],vA[vI[1]],vA[vI[2],... .一个示例用法是将 vI 初始化为一组 vA.size() 索引,从 0 到 vA.size()-1,然后根据 vA 对 vI 进行排序(使用 vA[vI[...]] 进行比较)。然后可以使用 reorder 函数对 vA 根据 vI 进行排序。
将初始 vA 视为已排序 vA 的排列。在根据 vA 对 vI 进行排序之后,然后根据 vI 对 vA 重新排序“取消排列” vA 回到排序后的排列。使用下面显示的示例函数,重新排序 vA 也会将 vI 重新排序回其初始化状态(0 到 vA.size()-1)。
【问题讨论】:
我认为您正在尝试执行“收集”功能。如果你想要它已经在 boost 库中实现 (boost/algorithm/gather.hpp) boost.org/doc/libs/1_41_0/doc/html/boost/mpi/gather.html 这里的目标是重新排序。制作有序副本很容易: for(i = 0; i 我更新了这个问题,加入了上一个问题的链接。 【参考方案1】:下面的示例显示了一个名为 reorderfail() 的非工作版本的重新排序,然后是一个名为 reorder() 的工作版本。这两个函数都将 vI 返回到其原始状态 0 到 vA.size()-1,但 reorderfail() 无法正确重新排序 vA,因为它缺少“取消置换”vA 所需的间接级别。
#include <algorithm>
#include <vector>
using namespace std;
template <class T>
void reorderfail(vector<T>& vA, vector<size_t>& vI)
size_t i, j;
for(i = 0; i < vA.size(); i++ )
while(i != (j = vI[i]))
swap(vA[i], vA[j]);
swap(vI[i], vI[j]);
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)
size_t i, j, k;
for(i = 0; i < vA.size(); i++)
while(i != (j = vI[i]))
k = vI[j];
swap(vA[j], vA[k]);
swap(vI[i], vI[j]);
int main( )
char A[] = 'b', 'c', 'a' ;
size_t I[] = 2 , 0 , 1 ; // order should be A[2] A[0] A[1]
size_t size = sizeof(A) / sizeof(*A);
vector<char> vA(size);
vector<size_t> vI(size);
vA.assign(A, A + size);
vI.assign(I, I + size);
reorderfail(vA, vI); // returns vA = 'c', 'a', 'b';
vA.assign(A, A + size);
vI.assign(I, I + size);
reorder(vA, vI); // returns vA = 'a', 'b', 'c';
return(0);
【讨论】:
【参考方案2】:移动数据而不是交换数据的工作重排序版本。这个例子可能更容易解释。每个排列都是一组“循环”。通过撤消循环来重新排序。假设有 8 个元素,并且 vI 包含所需的顺序。我把索引 i 放在了 vi 上面:
i : 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7
vI[i] = 5 , 7 , 0 , 3 , 6 , 2 , 4 , 1
循环 1:vI[0] == 5,vI[5] == 2,vI[2] == 0。
循环 2:vi[1] == 7,vi[7] == 1。
循环 3:vI[3] == 3。
循环 4:vI[4] == 6,vi[6] == 4。
撤销循环1,t = vA[0],vA[0] = vA[5],vA[5] = vA[2],vA[2] = t。
撤销循环2,t = vA[1],vA[1] = vA[7],vA[7] = t。
撤消循环 3,无需更正
撤销循环4,t = vA[4],vA[4] = vA[6],vA[6] = t。
每次在 vA[k] 中存储一个值时,vI[k] 被设置为 k,表示 vA[k] 是有序的。
template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)
size_t i, j, k;
T t;
for(i = 0; i < vA.size(); i++)
if(i != vI[i])
t = vA[i];
k = i;
while(i != (j = vI[k]))
// every move places a value in it's final location
vA[k] = vA[j];
vI[k] = k;
k = j;
vA[k] = t;
vI[k] = k;
【讨论】:
以上是关于根据索引向量重新排序向量 - 更新的主要内容,如果未能解决你的问题,请参考以下文章
如何根据已排序索引的向量对 std::set 索引进行排序?