给定一个任意的种子值,是否有任何已知的算法可以在线性时间和恒定空间(当输出迭代产生时)中产生一个改组范围[0..n]?
假设n可能很大,例如数以百万计,那么就不需要潜在地产生每个可能的排列,尤其是因为它是不可行的(种子值空间将需要很大)。这也是需要恒定空间的原因。(因此,我并不是特别在寻找数组改组算法,因为这要求将范围存储在长度为n的数组中,因此会使用线性空间。)
我知道问题162606,但是它没有提供对此特定问题的答案-从置换索引到该问题中给出的置换的映射将需要巨大的种子值空间。
理想情况下,它将像LCG一样工作,周期和范围为n,但是选择LCGa和选择cLCG的技巧很微妙。简单地满足LCG 的限制a并c在整个周期内都可以满足我的要求,但是我想知道是否还有更好的想法。
n
a
c
基于Jason的回答,我已经用C#实现了一个简单直接的实现。找到大于N的2的下一个最大幂。这使得生成a和c变得微不足道,因为c需要是相对质数的(意味着它不能被2整除,也就是奇数),而(a-1)需要可以被2整除,而(a-1)需要被4整除。从统计上讲,它需要1-2个全等才能生成下一个数字(因为2N> = M> = N)。
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(); } }