编译多个反向排列

时间:2014-04-28 09:43:39

标签: c arrays algorithm math permutation

抱歉,如果这不是一个合适的问题,那么过去几个小时我的思绪一直在流淌,我确信我错过了一些明显的东西!

我有一个系统设置,它可以多次交换数组中一系列条目的顺序。为此,我只是使用Fisher-Yates交换算法来创建一个相应的数组,其中相应的索引条目将移动到该数组。

所以我想要做的就是回到多个步骤。目前我正在试图找出如何使用交换数组中的两个信息编写如何在动态生成的数组中从第二次交换返回到原始顺序的方式。我假设一旦我能够构建一个可以一步回到两步的那个我继续应用相同的方法再回到另一个步骤。

使用swap [0],swap [1]和arr [1]的信息构建{'a','b','c','d'}数组的最简单方法是什么? ? 下面的代码几乎是伪代码,除了生成反向排列之外,一切都在实际程序中正常工作。

    char theOriginal[4] = {'a', 'b', 'c', 'd'}; //the initial order
    int swap[x][4];
    char arr[x][4];

    /*below code would actually be generated using functions*/
    swap[0] = GetSwap(4); //eg. returns {2,3,0,1} generated using a Fisher-Yates swap

    arr[0] = Swappit(theOriginal, swap[0]); //returns {'c', 'd', 'a', 'b'} permuted array produced by function which rearranged theOriginal's values to correspond with swap[0]

    //all entries after the first one built in a loop
    for(z=1; z<x; z++){
        swap[z] = GetSwap(4); //e.g. return {1,3,2,0} another permutation built the same way

        arr[z] = Swappit(arr[z-1], swap[z]); //from swap[z]  applied to arr[0], we get {'d','b','a','c'}
    }

如果该代码太容易混淆,无法轻易给出答案,那么可以使用更简单的代码:

    char letters[4] = {'a', b', 'c', 'd'};

    int move1[4] = {2, 3, 0, 1};
    char reorder1[4] = {'c', 'd', 'a', 'b'};

    int move2[4] = {1, 3, 2, 0};
    char reorder2[4] = {'d', 'b', 'a', 'c'};

    /**something happens here so that using move1 and move2, 
    a new integer array can be built which will give a third 
    reordering which matches letters, ie the follow outputs**/
    int moveBack[4] = {2, 1, 3, 0};
    char reorderBack = {'a', 'b', 'c', 'd'};

1 个答案:

答案 0 :(得分:1)

您只需计算每个步骤的逆置换并按相反的顺序应用它们。

如果您将前向置换P定义为

moveP[0] = n0
moveP[1] = n1
moveP[2] = n2
moveP[3] = n3

然后计算相应的逆置换P -1 ,例如

movePinv[n0] = 0
movePinv[n1] = 1
movePinv[n2] = 2
movePinv[n3] = 3

如果P(X)= Y,那么你有P -1 (Y)= X。

在您的示例中,如果从数组A0开始并应用2个排列P和Q,给出步骤A1 = P(A0)和A2 = Q(A1)= Q(P(A0)),然后返回在初始数组A0中,必须以相反的顺序将逆排列应用于最终数组。即A1 = Q -1 (A2)则A0 = P -1 (A1)= P -1 (Q - 1 (A2))。

请注意,为了提高内存使用率,您肯定可以逐步执行此操作,在一个内容中累积所有反向排列(假设您只对检索初始顺序感兴趣,但当然不会检索中间步骤)。

编辑:关注您的代码,以下是落后的步骤。如果你打算多次这样做,那显然不是很好(因为反向排列将被计算并且每次都应用于源数组),但对于一次性,这是最简单的方法。

int backFrom = x - 1, backTo = 0; // for example
char state[4] = arr[backFrom];
int swapInvAux[4];

for (z = backFrom; z >= backTo; --z)
{
    swapInvAux = InversePermutation(swap[z]);

    state = Swappit(state, swapInvAux);
}

为了获得更好的性能,与交换数组并行,您应该存储通过将Swappit函数应用于交换数组本身而获得的累积反向排列链。这样,您就可以在一个步骤中将最终状态转换为任何中间状态。