根据索引向量重新排序向量 - 更新

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 索引进行排序?

Groupby 一列并根据 R 中的字符串向量重新排列另一列字符串

在 C++ 中,如何获取指向向量的指针?

合并排序 - 向量不排序

如何获取向量的排序索引?