我想以非顺序方式遍历集合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的另一个元素。
如何生成这样的函数或者是否有任何已知的函数可以执行此操作?
答案 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)
表示某些常量a
,c
和m
。在这种情况下,m = 65536
。
如果以下属性成立,则LCG具有完整期间(您想要的属性):
c
和m
相对较为优秀。a-1
可被m
的所有素数因子整除。m
是4的倍数,a-1
是4的倍数。我们将使用a = 5
,c = 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;
享受