什么函数伪随机重新排序N项?

时间:2015-07-29 07:14:59

标签: algorithm math set bijection

自然数为1到N(N大约为1e7),我梦想有一种功能可以通过一组相当短的参数重新排序集合,定义,与值。

对于N = 2^i - 1,这可能只是位重新排序,因此,i 的一组0..i值定义了突变。

我正在寻找一种类似漂亮的方式,适用于任意N.

位重新排序示例。 8个值:0..7使用3位编码:000 – 111。为了重新排序该集,我存储了每个位的新位置。取一个数组[0,1,2]并随机重新排序,然后将结果存储为置换键。即[1,0,2]将重新排序8个值,如下所示:

   210   201   
0: 000 - 000 :0
1: 001 - 010 :2
2: 010 - 001 :1
3: 011 - 011 :3
4: 100 - 100 :4
5: 101 - 110 :6
6: 110 - 101 :5
7: 111 - 111 :7

3 个答案:

答案 0 :(得分:3)

正如评论中所指出的,您对使用短密钥对N!个排列中的任意一个进行编码不感兴趣;你只是想找一种方法来确定性地选择一个短按键的排列。

我建议你需要做的就是

  • 选择你最喜欢的伪随机数生成器;
  • 使用您已知的短键种子
  • 使用它从您的N项目列表
  • 中选择值

答案 1 :(得分:2)

我不太清楚我是否理解你的问题,但是你可以循环读取1..N中的数字,并且对于每个步骤i,生成1 ... N范围内的伪随机数j,然后交换我和j。

答案 2 :(得分:2)

不消耗内存的简单方法是将每个数乘以与N互质的常数,然后像这样计算除以N的余数(例如Java):

static int reorder(int input, int N) {
    // 15485863 is prime, thus coprime with any lesser N
    return (int) ((input * 15485863L) % N);
}

使用N = 10345560进行测试:

public static void main(String[] args) {
    int N = 10345560;
    int[] source = IntStream.range(0, N).toArray();
    int[] reordered = IntStream.of(source).map(i -> reorder(i, N)).toArray();
    // Check that all reordered numbers are within 0..N-1
    assert IntStream.of(reordered).allMatch(i -> i >= 0 && i < N);
    // Check that all numbers are different
    assert IntStream.of(reordered).distinct().count() == N;
}

优点是您不需要中间内存来存储所有数字:您可以以流方式处理它们(例如,从一个文件读取并将结果写入另一个文件)。

缺点是,对于提供的参数,您必须测试它与N的互质并拒绝或调整它,如果不是。