Generating shuffled range using a PRNG rather than shuffling

前端 未结 5 2007
孤城傲影
孤城傲影 2020-12-01 04:55

Is there any known algorithm that can generate a shuffled range [0..n) in linear time and constant space (when output produced iteratively), given an arbitrary seed value?

5条回答
  •  时光说笑
    2020-12-01 05:17

    Based on Jason's answer, I've made a simple straightforward implementation in C#. Find the next largest power of two greater than N. This makes it trivial to generate a and c, since c needs to be relatively prime (meaning it can't be divisible by 2, aka odd), and (a-1) needs to be divisible by 2, and (a-1) needs to be divisible by 4. Statistically, it should take 1-2 congruences to generate the next number (since 2N >= M >= N).

    class Program
    {
        IEnumerable 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();
        }
    }
    

提交回复
热议问题