1. 程式人生 > >隨機生成0到n之間的m個數

隨機生成0到n之間的m個數

如何用隨機數生成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個數是等概率取到的