隨機生成器

  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的地方取得,此時我有更大比率的序列用於生成,換句話說被拋掉的更少了,這樣作是爲了不大量生成了丟棄序列而使得生成速率減慢,其它的沒什麼特別的意思。

相關文章
相關標籤/搜索