隨機生成0到n之間的m個數
阿新 • • 發佈:2019-01-03
如何用隨機數生成0到n之間的m個不重複的數
1、最直接的方法就是先隨機生成一個0到n之間的數,判斷這個數是否已被選上,如果以前沒選過,則選上,如果以前已選,則丟棄
void common(int n,int m) { int * randnum=(int *)malloc(n*sizeof(int)); memset(randnum,0,n*sizeof(int)); //把n個位置全部置0 srand(time(NULL)); while(m) { int cur=rand()%n; if (randnum[cur]==0) //進行判斷,如果當前數沒有選擇過,則選擇並輸出 { cout<<cur<<endl; randnum[cur]=1; m--; } } free(randnum); }
這種方法簡單易懂,但是需要額外的空間來確保取出的數不重複,那麼我們有沒有更為簡單的方法呢,答案是肯定的
2、先上程式碼,後做解釋
void mRand(int n ,int m)
{
srand(time(NULL));
for (int i=0;i<n;i++)
{
if(rand()%(n-i)<m)
{
cout<<i<<endl;
m--;
}
}
}
上邊的程式碼雖然簡潔,但是不易懂,我們接下來說明一下
首先是一個迴圈,這個迴圈確保了輸出的數是不重複的,因為每次的i都不一樣
其次是m個數,在每次迴圈中都會用rand()%(n-i)<m來判斷這個數是否小於m,如果符合條件則m減1,直到為0,說明已經取到m個數了
再次是如何保證這m個數是等概率取到的
在第一次迴圈中i=0, n-i=n, 則隨機數生成的是0-n-1之間的隨機數,那麼此刻0被取到的概率為 m/n-1
在第二次迴圈中i=1,n-i=n-1,則隨機數生成的是0-n-2之間的隨機數,這時1被取到的概率就和上一次迴圈中0有沒有取到有關係了。假設在上一次迴圈中,沒有取,則這次取到的1的概率為 m/n-2;假設上一次迴圈中,已經取到了,那麼這次取到1的概率為m-1/n-2,所以總體上這次被取到的概率為 (1-m/n-1)*(m/n-2)+(m/n-1)*(m-1/n-2),最後通分合並之後的結果為m/n-1和第一次的概率一樣的
同理,在第i次迴圈中,i被取上的概率也為m/n-1
所以這m個數是等概率取到的