有效地计算随机排列中的第n项
Efficient calculation of nth item in a random permutation
想象一下,我可以使用Knuth洗牌和一个带有密钥的种子随机数生成器来洗牌0到2^32之间的所有数字。
从概念上讲,我需要两个数组(为简洁起见,使用Z5而不是Z232):[2, 0, 1, 4, 3] // perm
[1, 2, 0, 4, 3] // inv === p^-1
如果我有这些数组,我可以有效地查找排列中的第n个元素以及找出排列值v中的第1个元素;
v = perm[n];
n == inv[v]; // true
我不想存储两个16 GB的int数组来表示这个洗牌集合,因为我在任何时候都不会对整个洗牌序列感兴趣。我只对第n个元素的值感兴趣
理想情况下,我想写两个这样的纯函数:
uint nthShuffled = permutate<uint>(key, n); // O(log n)
uint n == invert<uint>(key, nthShuffled); // O(log n)
要求:
- 每个32位的值映射到一个唯一的不同的32位值。
- 对排列中前100个元素的了解并不能提供排列中第101个元素的信息。
我明白,理论上必须有至少232!唯一键来表示任何可能的排列,但我相信在实践中我可以把这个问题隐藏在一个好的哈希函数后面。
有什么东西能接近这个吗?
任何分组密码实际上都是一个伪随机排列。32位分组密码将0
和2 ^ 32 - 1
之间的整数进行排列。
给定一个密钥,用这个密钥加密N-th
,得到CC_4的伪随机数。
唯一的问题是找到一个好的32位分组密码。我唯一知道的是SKIP32,但我对它的强度一无所知。
SKIP32的密钥大小为80位。如果它是一个好的密码,那就足够了。
但是,我还是不知道密码。
如果将范围增加到2 ^ 64 - 1
整数是您的选择,您可以简单地使用众所周知的64位分组密码,如Triple-DES或Blowfish。
"知道了排列中的前100个元素,就无法知道排列中的第101个元素是什么。"
需要将整个数组存储在内存中。我建议使用stxxl,它是通过将容器的大部分存储在磁盘上而为大型数据类型设计的。根据随机排列的本质,在给定[n]的情况下,你不能推断[n-1]或[n+1]的值。所以看起来空间不像是可以优化的
从密码学的角度来看,您需要使用32位块的分组密码。
在任意(通常很小)域上的加密(又名"键控排列")问题就是保持格式加密的问题。
对于这个特定的问题,有一个通用的"完美"解决方案——但是计算涉及到通过超几何分布进行采样,这意味着大量的浮点数和任意精度数的混淆,这是昂贵的。
也存在"近似"解,其中排列不是严格地在所有可能的排列中均匀选择的,但差异可以任意小,以至于无法区分实现的排列和真正随机选择的排列。具体参见索普洗牌。
没有标准和安全的32位分组密码,因为32位不足以确保在通常使用分组密码的情况下的安全性(加密长数据流,例如作为SSL的一部分);64位块已经不受欢迎了。所以你得靠自己了
哈希不能解决随机数序列
存储2^32位。那是0.5 GB。
运行fisher - yates洗牌,并在你进行的过程中"划掉"比特。如果你想知道第5个元素的内容,你可以划掉4,第5个随机值就是你的数字。
要得到第n个排列,你需要回溯。运行n次算法,得到如下数字:
Find 5th index after 4 permutations:
First iteration:
1st : skip (run through the RNG)
2nd : skip
3rd : skip
4th : 7th index to 5th index
Second iteration: (run using same seed as 1st iteration)
1st : skip
2nd : skip
3rd : 3rd index to 7th index
4th : 7th index to 5th index
Third iteration:
1st : skip
2nd : 4th index to 7th index
3rd : 3rd index to 7th index
4th : 7th index to 5th index
Fourth iteration:
1st : 8th index to 4th index
2nd : 4th index to 7th index
3rd : 3rd index to 7th index
4th : 7th index to 5th index
在最后一次迭代时,你知道第8个索引变成了第5个索引。
编辑:我写了一个快速的程序来测试速度。每个排列都需要几分钟。虽然速度很慢,但仍然可用。- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 递归函数计算序列中的平方和(并输出过程)
- 为什么 Serial.println(<char[]>);返回随机字符?
- (C++)分析树以计算返回错误值的简单算术表达式
- 我的字符计数代码计算错误.为什么
- 字符串-C++后显示的随机字符
- 在计算中使用二的幂有多有利可图
- 如何计算文件中的"columns"数?
- 计算排序向量的向量中唯一值的计数
- 如何使用 std::累积在 C++ 中计算总和立方体
- 循环中的随机函数
- 对于C++随机访问迭代器(矢量迭代器),迭代器之间的差异是如何计算的?
- 如何生成统一的随机二进制数以成对计算C++中的汉明距离?
- 从多个线程组随机计算着着色器写入RWStructuredBuffer
- 使用随机生成的C++数字进行计算
- 在每台计算机上生成相同的随机排列
- 有效地计算随机排列中的第n项
- 二维数组,计算并存储6个随机连接点
- 有没有办法在不计算 CDF 的情况下从非标准分布生成随机变量