我們不得不承認這樣一個事實:那就是儘管在高級程序語言設計中包含了類似於Random產生隨機數之類的方法,但是它產生的隨機數並不能滿足我們日常所有需要,因爲它可能重複——設想一下,電子化抽取試題的原理就是根據預定產生的題目數量產生果敢若干個對應的隨機數,然後將匹配的試題抽取、排序並打印在試卷上。但是在同一次考試時候不允許同一題目出現重複(儘管這樣的概率很低,但是我們絕對不允許這樣做!)。所以避免產生重複隨機數的方法(產生“真正的隨機數”)成了我們必須研究的話題。今天本文就討論一下。
這是最容易想到的方法,逐個產生這些隨機數,每產生一個,都跟前面的隨機數比較,如果重複,就重新產生。這種方法效率比較低,且比較次數呈線性增長,越往後次數越多。
所謂“篩選法”就是根據要產生隨機數指定的範圍(起始數必須小於終止數),將這些數全部裝入一個數組,然後利用系統隨機函數(比如 Random )隨機產生一個下標,將這個下標對應的數值返回並刪除對應的這個數,直到這個數組爲空。
public sealed class TureRandom
{
private ArrayList nums=new ArrayList();
public TureRandom (int startnum, int endnum)
{
if (startnum >= endnum)
throw new Exception("對不起,起始數字必須小於結尾數字!")
else
for (int i=startnum; i<=endnum;++i)
nums.Add(i);
}
public int GetNum()
{
if (nums.Count <= 0) Then
throw new Exception("對不起,指定範圍的隨機數全部產生過了。")
else
{
Random r = new Random();
int index=(int)(r.NextDouble()*10+1);
int returnnum =(int)(nums[index]);
nums.RemoveAt(index);
return returnnum;
}
}
}
方法3:
int a[100]={0};
int i, m;
for(i=1; i<=99; ++i)
{
while(a[m=rand()%100]);
a[m] = i;
}
這段代碼也是隨機產生位置,但它預先把整個數組初始化爲0,然後隨機產生其中一個位置,如果該元素值爲0,表示這個位置還沒有被使用過,就把i賦予它;否則,就重新隨機產生另一個位置,直到整個數組被填滿。
方法4:
int a[100];
for(i=0; i<=99; ++i) a[i]=i;
for(i=99; i>=1; --i) swap(a[i], a[rand()%i]);
上面這段代碼只需要遍歷一次就可以產生這100個不重複的隨機數,它是如何做到的呢?首先第二行按順序用0到99填滿整個數組;第三行,是隨機產生從0到m-2個數組下標,把這個下標的元素值跟m-1下標的元素值交換,一直進行到下標爲1的元素。因此它只需要遍歷一次就能產生全部的隨機數。
轉載出處:http://blog.chinaunix.net/uid-20384806-id-1954354.html
關於這些方法中算法的性能和效率,參閱:http://www.cnblogs.com/eaglet/archive/2011/01/17/1937083.html。
http://www.nowamagic.net/program/program_GenerateRandomNumbers.php