代码之家  ›  专栏  ›  技术社区  ›  Barry Kelly

使用PRNG而不是混洗生成混洗范围

  •  22
  • Barry Kelly  · 技术社区  · 17 年前

    假设n可能很大,例如数以百万计,因此不需要潜在地产生所有可能的排列,尤其是因为它不可行(种子值空间需要很大)。这也是需要恒定空间的原因。(因此,我并不特别寻找数组洗牌算法,因为这需要将范围存储在长度为n的数组中,因此将使用线性空间。)

    question 162606 ,但它并没有给出这个特定问题的答案-从置换索引到该问题中给出的置换的映射将需要一个巨大的种子值空间。

    理想情况下,它会像一个 LCG n ,但是选择的艺术 a c C 在一个完整的时期内,LCG可能满足我的要求,但我想知道是否有更好的想法。

    5 回复  |  直到 9 年前
        1
  •  7
  •   Community Mohan Dere    9 年前

    基于 Jason's answer

    class Program
    {
        IEnumerable<int> GenerateSequence(int N)
        {
            Random r = new Random();
            int M = NextLargestPowerOfTwo(N);
            int c = r.Next(M / 2) * 2 + 1; // make c any odd number between 0 and M
            int a = r.Next(M / 4) * 4 + 1; // M = 2^m, so make (a-1) divisible by all prime factors, and 4
    
            int start = r.Next(M);
            int x = start;
            do
            {
                x = (a * x + c) % M;
                if (x < N)
                    yield return x;
            } while (x != start);
        }
    
        int NextLargestPowerOfTwo(int n)
        {
            n |= (n >> 1);
            n |= (n >> 2);
            n |= (n >> 4);
            n |= (n >> 8);
            n |= (n >> 16);
            return (n + 1);
        }
    
        static void Main(string[] args)
        {
            Program p = new Program();
            foreach (int n in p.GenerateSequence(1000))
            {
                Console.WriteLine(n);
            }
    
            Console.ReadKey();
        }
    }
    
        2
  •  6
  •   Community Mohan Dere    9 年前

    下面是 Linear Congruential Generator 从…起 FryGuy's answer

    import random
    import math
    
    def lcg(start, stop):
        N = stop - start
    
        # M is the next largest power of 2
        M = int(math.pow(2, math.ceil(math.log(N+1, 2))))
    
        # c is any odd number between 0 and M
        c = random.randint(0, M/2 - 1) * 2 + 1
    
        # M=2^m, so make (a-1) divisible by all prime factors and 4
        a = random.randint(0, M/4 - 1) * 4 + 1
    
        first = random.randint(0, M - 1)
        x = first
        while True:
            x = (a * x + c) % M
            if x < N:
                yield start + x
            if x == first:
                break
    
    if __name__ == "__main__":
        for x in lcg(100, 200):
            print x,
    
        3
  •  5
  •   Jason S    17 年前

    听起来你想要一个算法,它保证产生一个从0到n-1的循环,没有任何重复。几乎可以肯定的是,根据您的需求,会有一大堆这样的问题; group theory 如果你想深入研究数学背后的理论,这将是数学中最有用的分支。

    如果您想要快速且不关心可预测性/安全性/统计模式,LCG可能是最简单的方法。您链接到的wikipedia页面包含以下(相当简单)要求:

    m、 而对于一些选择,一个少得多 比那还多。LCG将有一个完整的 当且仅当:

    1. c和m是相对素数,

    K -1>=n会让你使用 linear feedback shift registers (LFSR)。或者找到您最喜欢的加密算法(RSA、AES、DES,无论什么),并给定一个特定的密钥,计算出它所分配的数字的空间N,并为每个步骤应用一次加密。

        4
  •  2
  •   Nick Johnson    17 年前

    请参阅我的文章 secure permutations with block ciphers 这是一种方法。

        5
  •  1
  •   erikkallen    17 年前

    看看线性反馈移位寄存器,它们正好可以用于此。 解释它们的简单方法是从种子开始,然后使用公式进行迭代

    x = (x << 1) | f(x)
    

    其中f(x)只能返回0或1。

    f 可以找到示例函数 here ,例如,对于63个值,您可以使用

    f(x) = ((x >> 6) & 1) ^ ((x >> 5) & 1)