随机生成器

  1. 在不知道文件总行数的状况下,如何从文件中随机的抽取一行或是k行。
  2. 已知random_m()随机数生成器的范围是[1, m] 求random_n()生成[1, n]范围的函数,m < n && n <= m *m。
  3. 已知一随机发生器,产生0的几率是p,产生1的几率是1-p。如今要你构造一个发生器, 使得它构造0和1的几率均为1/2;构造一个发生器,使得它构造一、二、3的几率均为1/3;构造一个发生器,使得它构造一、二、三、…n的几率均为1/n,要求复杂度最低。

一、思路:ios

  蓄水池问题:当n≤k时,序号为n的这个数放入容量为k的容器中,表示该数确定会被选中;当n>k时,要使得前n个数每一个数被选中的几率都是k⁄n。dom

  证实:假设n≥k,前n个数每一个数被选中的几率都是k⁄n,则须要概括证实前n+1个数每一个数被选中的几率是k⁄(n+1)。函数

  分两个角度去思考这个问题:一是第n+1个被选中的几率,很显然是k⁄(n+1)。二是第一、二、...、n个数被选中的几率也要是k⁄(n+1)。spa

  后者分析:以第m个数为例(k<m<n+1),它被选中的几率为”m被选中的几率*[m后面元素没有被选中+m后面的元素被选中*可是m没被替换的几率]“。code

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <ctime>
 4 
 5 using namespace std;
 6 
 7 void SamplePool(int *data, int n, int m)
 8 {
 9     int i, s;
10     srand(time(0));
11     for (i = m; i < n; i++)
12     {
13         s = rand() % i;
14         if (s < m)
15             swap(data[i], data[s]);
16     }
17     for (i = 0; i < m; i++)
18         cout << data[i] << ' ';
19     cout << endl;
20 }
21 
22 int main()
23 {
24     int data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
25     SamplePool(data, 10, 5);
26     return 0;
27 }

 

二、思路:blog

  假设要求[1,5]随机一个[1,7]。则先用[1,5]随机生成[1,25],再经过拒绝采样定理选取[1,21],其中选21而不选7的缘由是提升随机生成的效率。事件

  首先,将(1,5)之间的随机发生器使用两次,按照五进制进行使用,拼成一个(1,25)的随即发生器既:([gen][gen]),每一[]为一个5进制上的位,换算为十进制为:x=gen*5+gen。在十进制上的范围为:6-30,进行一个简单的左移动,可换算成1-25范围上的值;而后将(1,25)平均分配到7中状况上面,考虑21是7的倍数,所以能够每三个作一个映射(固然,也能够无论,直接截断7后面的数字,可是范围过小,效率不高),ƒ(1~3) = 1,ƒ(4~6) = 2,此时就是等几率的,若是产生了22-25之间的数字,则拒绝采样。资源

 1 int Rand_M2N(int m, int n)
 2 {
 3     srand(time(0));
 4     int i, s, t, k;  
 5     //k是n的最大倍数,可是小于m*m;t是倍数的量。
 6     for (i = 1; i <= MAX; i++)
 7     {
 8         if (i * n < m * m)
 9         {
10             k = i * n;
11             t = i;
12         }
13         else
14             break;
15     }
16     cout << "k: " << k << endl;
17     //s是被随机选中的数。
18     do
19     {
20         s = m * (rand() % m) + (rand() % m + 1);
21     }while(s > k);  
22     if (s % t == 0)
23         return s / t;
24     else
25         return s / t + 1;
26 }

 

三、思路:it

  思考角度1:生成1,2,…n的几率分别是1/n,也就是均等的。那么咱们能够想怎么生成一个序列,里面有n个独立事件,几率是相等。并且咱们可以猜想到这些几率的形式为px(1-p)y,若是要相等,那么x必须等于y。这样就说明了序列中0和1的个数是相等的。并且这样的状况必须有多于n个状况才行。io

  思考角度2:而后是1/n的状况了,咱们以5为例,此时咱们取x=2,由于C(2x,x)=C(4,2)=6是比5大的最小的x,此时咱们就是一次性生成4位二进制,把1出现个数不是2的都丢弃,这时候剩下六个:0011,0101,0110,1001,1010,1100,取最小的5个,即丢弃1100,那么咱们对于前5个分别编号1到5,这时候他们的几率都是p*p*(1-p)*(1-p)相等。关键是找那个最小的x,使得C(2x,x)>=n这样能提高查找效率。我之因此取C(2x,x)是为了让一样的序列长度下可用的资源尽可能多,由于C(n,i)最大是在i接近n/2的地方取得,此时我有更大比率的序列用于生成,换句话说被抛掉的更少了,这样作是为了不大量生成了丢弃序列而使得生成速率减慢,其它的没什么特别的意思。

相关文章
相关标签/搜索