在一组上生成可逆排列

时间:2014-07-13 11:39:25

标签: function permutation algebra bijection

我想以非顺序方式遍历集合Q = [0,2 ^ 16]中的所有元素。为此,我需要函数f(x)Q - > Q给出了对集合进行排序的顺序。例如:

f(0) = 2345   
f(1) = 4364   
f(2) = 24   
(...)

为了恢复顺序,我需要反函数f'(x)Q - > Q将输出:

f(2345) = 0
f(4364) = 1
f(24) = 2
(...)

该函数必须是双射的,对于Q的每个元素,函数唯一地映射到Q的另一个元素。

如何生成这样的函数或者是否有任何已知的函数可以执行此操作?

2 个答案:

答案 0 :(得分:3)

编辑:在下面的回答中,f(x)是“x之后的内容”,而不是“x位置的内容”。例如,如果您的第一个数字是5,那么f(5)是下一个元素,而不是f(1)。回想起来,你可能认为f(x)是“x位置”。如果用作“位置x的内容”,则此答案中定义的函数较弱。


Linear congruential generators符合您的需求。

线性同余生成器由等式

定义
f(x) = a*x+c (mod m)

表示某些常量acm。在这种情况下,m = 65536

如果以下属性成立,则LCG具有完整期间(您想要的属性):

  1. cm相对较为优秀。
  2. a-1可被m的所有素数因子整除。
  3. 如果m是4的倍数,a-1是4的倍数。
  4. 我们将使用a = 5c = 1

    要反转LCG,我们会根据f(x)求解x

    x = (a^-1)*(f(x) - c) (mod m)
    

    我们可以通过extended Euclidean algorithm找到5 mod 65536的逆,或者因为我们只需要这个计算,我们可以将它插入Wolfram Alpha。结果是52429。

    因此,我们有

    f(x) = (5*x + 1) % 65536
    f^-1(x) = (52429 * (x - 1)) % 65536
    

答案 1 :(得分:0)

有很多方法可以解决这个问题。

由于您的设置大小很小,因此可以通过内存查找简单地完成生成函数及其逆的要求。因此,一旦选择了排列,就可以在查找表中存储正向和反向。

创建排列的一种方法是将数组中的所有元素映射出来,然后随机地交换它们“足够”。 C代码:

int f[PERM_SIZE], inv_f[PERM_SIZE];
int i;

// start out with identity permutation
for (i=0; i < PERM_SIZE; ++i) {
    f[i] = i;
    inv_f[i] = i;
}

// seed your random number generator
srand(SEED);

// look "enough" times, where we choose "enough" = size of array
for (i=0; i < PERM_SIZE; ++i) {
    int j, k;
    j = rand()%PERM_SIZE;
    k = rand()%PERM_SIZE;
    swap( &f[i], &f[j] );
}

// create inverse of f
for (i=0; i < PERM_SIZE; ++i)
    inv_f[f[i]] = i;

享受