Algorithm 范围内非重复随机搜索算法
我正在寻找一种高效的算法,可以在一定范围内生成随机值,而不需要重复 在伪代码中:(在类Rand中) 用法:Algorithm 范围内非重复随机搜索算法,algorithm,random,non-repetitive,Algorithm,Random,Non Repetitive,我正在寻找一种高效的算法,可以在一定范围内生成随机值,而不需要重复 在伪代码中:(在类Rand中) 用法: Rand r = new Rand(1, 100000000); long x = r.getNumber(); long y = r.getNumber(); ... 从r.getNumber()返回的数字应始终与以前返回的数字不同。 当然,如果返回了to-from+1数字,那么算法应该重新开始(或者出错——无论如何都不重要) 请注意,范围可能非常大,因此随机排列的数
Rand r = new Rand(1, 100000000);
long x = r.getNumber();
long y = r.getNumber();
...
从r.getNumber()返回的数字应始终与以前返回的数字不同。当然,如果返回了
to-from+1
数字,那么算法应该重新开始(或者出错——无论如何都不重要)
请注意,范围可能非常大,因此随机排列的数组(最初包含
[from,to]
数字)可能会使内存溢出。一种方法是生成一个介于from和to之间的数字列表,随机删除这些数字,直到袋子变空,然后重新填充。为了节省大范围的存储空间,您可以将拾取的数字记录到某一点(在选择复制品时重新拾取),因为拾取复制品的概率最初应该很低。确定最佳过渡点可能是一项经验性工作
编辑:还有一些想法
对于真正的大范围,即使这样也不能在内存限制下提供良好的性能。一个想法可能是将候选对象存储为间隔,而不是作为数字列表。因此,最初,您可以在从和到之间进行选择,得到x1。下次,从第一个子区间或第二个子区间中选择一个数字,概率与区间长度成比例。在每个步骤中,消除长度为零的间隔。这需要存储M+2个整数(在最坏的情况下),其中M是绘制的数量,或者N/2渐近地存储大N(在最坏的情况下),其中N是初始间隔大小。不过,也许有人会仔细检查我 一种方法是生成一个介于from和to之间的数字列表,随机删除这些数字,直到袋子变空,然后重新填充。为了节省大范围的存储空间,您可以将拾取的数字记录到某一点(在选择复制品时重新拾取),因为拾取复制品的概率最初应该很低。确定最佳过渡点可能是一项经验性工作 编辑:还有一些想法
对于真正的大范围,即使这样也不能在内存限制下提供良好的性能。一个想法可能是将候选对象存储为间隔,而不是作为数字列表。因此,最初,您可以在从和到之间进行选择,得到x1。下次,从第一个子区间或第二个子区间中选择一个数字,概率与区间长度成比例。在每个步骤中,消除长度为零的间隔。这需要存储M+2个整数(在最坏的情况下),其中M是绘制的数量,或者N/2渐近地存储大N(在最坏的情况下),其中N是初始间隔大小。不过,也许有人会仔细检查我 如果不要求间隔中的每个数字最终出现,可以使用: 它是周期性的,新的周期从种子等于初始值开始,周期的长度取决于A和C的选择 优点:O(1)时间和空间,缺点:并非间隔中的每个数字都会出现
对于长度为2^m的间隔,请看我没有使用它,但wikipedia说它可能是最大长度,也就是说,您可以在输出中显示所有数字(除一个以外)。如果您不要求间隔中的每个数字最终都显示,您可以使用: 它是周期性的,新的周期从种子等于初始值开始,周期的长度取决于A和C的选择 优点:O(1)时间和空间,缺点:并非间隔中的每个数字都会出现
对于长度为2^m的间隔,请看我没有使用它,但wikipedia说它可能是最大长度,也就是说,您可以在输出中显示所有数字(除一个以外)。关于起点的一些想法: 1) 假设你有一个函数f(x),它是1..N上的一个置换,其中N大于你的范围。如果将其应用于范围内的x,则可能会产生非法值-超出范围的值。您可以通过对非法值再次调用f来定义范围内的置换。你最终会得到一个合法值,因为序列x,f(x),f^2(x),f^3(x)最终必须循环,如果最坏的情况发生,它将在x处返回 2) 有一些交换网络可以让你在N个对象上产生所有可能的排列,例如(有趣的URL-Benes网络)。通过随机设置开关,可以在N个对象上获得任意排列,其中N可能是2的幂。因为将有K个开关,所以有2^K种设置它们的方法,这意味着您没有M!概率相等的排列,但也许你不会介意,或者可以通过多次重复来最小化非随机性
3) 如果您准备通过多次应用许多不同的基本置换来实现近似随机性,您可以尝试在整个范围内交替添加mod N,然后将范围拆分为子范围,例如,对于范围内的一些p-1值拉伸,应用通过乘以一些k模式p产生的置换。我们希望,尽管每个步骤都非常基本,但只要应用足够多的步骤并使它们足够多样化,结果就会接近随机,特别是如果您随机选择参数。关于起点的一些想法: 1) 假设你有一个函数f(x),它是1..N上的一个置换,其中N大于你的范围。如果将其应用于范围内的x,则可能会产生非法值-超出范围的值。您可以通过对非法值再次调用f来定义范围内的置换。你最终会得到一个法律价值,因为
Rand r = new Rand(1, 100000000);
long x = r.getNumber();
long y = r.getNumber();
...
int getNumber() {
seed = (seed * A + C) mod (to-from);
return seed + to;
}
import random
def randomFromTo(FROM,TO,k): #k is the number of sample you want to generate
m= random.sample(xrange(FROM,TO),k)
return (i for i in m)
RandomGenerator=randomFromTo(10,1000000000,12)
for k in range(12):
print RandomGenerator.next()
57625960
50621599
2891457
56292598
54608718
45258991
24112743
55282480
28873528
1120483
56876700
98173231
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 9 16 13 20 12 3 1 5 28 7
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 22 11 26 29 20 1 3 6 7 10
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 1 11 16 7 22 26 3 25 8 9
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 7 17 3 22 21 24 27 12 28 2
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 30 21 23 2 27 24 3 18 25 19
> sample(x = 1:30, size = 10, replace = FALSE)
[1] 4 6 11 16 26 8 17 22 23 25
37 5 53 21 45 13 61 29 33 1 49 17 41 9 57 25 39 7 55 23 47 15 63 31 35 3 51 19 43 11 59 27 36 4 52 20 44 12 60 28 32 0 48 16 40 8 56 24 38 6 54 22 46 14 62 30 34 2 50 18 42 10 58 26
bits: 6, count: 64, set: 64
function math_random_filled_arithmetical($n,$max,$seed)
{
/*
- produces 0..max, repeatable, unique, one-to-one mapped random numbers
- uses arithmetic operations to imitate randomness
- $n: 0<=$n=<$max
- $max: any integer, not only power of two
- $seed: any string or number
*/
$n=intval($n);
$max=intval($max);
$opt1=$n;
$opt2=$max-$n;
$n2=min($opt1,$opt2);
$reverseit=crc32($seed.'internalseed'.$n2)&1;
if($opt1>$opt2) $reverseit=!$reverseit;
$max2=floor(intval($max-1)/2);
//echo "n:$n, max:$max,n2:$n2,max2:$max2,reverseit:$reverseit\n";
if($max>=3)
if($opt1!=$opt2)
$n2=math_random_filled_arithmetical($n2,$max2,$seed.'*');
$res=$reverseit? $max-$n2:$n2;
$res=intval(fmod($res+(crc32($seed)&(1<<30)),$max+1));
//echo "n:$n, max:$max, res:$res\n";
return $res;
}
//demonstration
$max=41;//-- test a max value
for($n=0;$n<=$max;$n++)
{
$r=math_random_filled_arithmetical($n,$max,$seed='someseed');
$ar[$r]=1;
echo " $r ";
}
$filled=0;
for($n=0;$n<=$max;$n++)
if(isset($ar[$n])) $filled++;
echo "\n count: ".($max+1).", filled: ". $filled."\n";
20 19 18 17 33 32 37 36 14 13 31 34 35 26 16 11 12 3 39 40 0 41 1 2 38 29 30 25 15 6 7 10 28 27 5 4 9 8 24 23 22 21
count: 42, filled: 42