天天看點

C# Random 生成不重複随機數 - 防空洞123

C# Random 生成不重複随機數

Random 類

命名空間:System

表示僞随機數生成器,一種能夠産生滿足某些随機性統計要求的數字序列的裝置。

僞随機數是以相同的機率從一組有限的數字中選取的。所選數字并不具有完全的随機性,因為它們是用一種确定的數學算法選擇的,但是從實用的角度而言,其随機程度已足夠了。

僞随機數的生成是從種子值開始。如果反複使用同一個種子,就會生成相同的數字系列。産生不同序列的一種方法是使種子值與時間相關,進而對于 Random 的每個新執行個體,都會産生不同的系列。預設情況下,Random 類的無參數構造函數使用系統時鐘生成其種子值,而參數化構造函數可根據目前時間的計時周期數采用 Int32 值。但是,因為時鐘的分辨率有限,是以,如果使用無參數構造函數連續建立不同的 Random 對象,就會建立生成相同随機數序列的随機數生成器。

通過建立單個而不是多個 Random 對象可以避免此問題。

若要提高性能,請建立一個随時間推移能生成多個随機數的 Random 對象,而不要反複建立會生成同一個随機數的 Random 對象。

Random 成員

名稱 ● 說明

Equals ● 确定指定的 Object 是否等于目前的 Object。(繼承自 Object。) 

Finalize ● 允許 Object 在“垃圾回收”回收 Object 之前嘗試釋放資源并執行其他清理操作。(繼承自 Object。) 

GetHashCode ● 用作特定類型的哈希函數。(繼承自 Object。) 

GetType ● 擷取目前執行個體的 Type。(繼承自 Object。) 

MemberwiseClone ● 建立目前 Object 的淺表副本。(繼承自 Object。) 

Next ● 已重載。 傳回随機數。 

NextBytes ● 用随機數填充指定位元組數組的元素。 

NextDouble ● 傳回一個介于 0.0 和 1.0 之間的随機數。 

Sample ● 傳回一個介于 0.0 和 1.0 之間的随機數。 

ToString ● 傳回表示目前 Object 的 String。(繼承自 Object。)

用 C# 生成不重複的随機數

我們可以使用兩種方式初始化一個随機數發生器:

第一種方法不指定随機種子,系統自動選取目前時間作為随機種子:

Random ro = new Random();

第二種方法可以指定一個int型參數作為随機種子:

int iSeed=10; 

Random ro = new Random(10); 

long tick = DateTime.Now.Ticks; 

Random ran = new Random((int)(tick & 0xffffffffL) | (int) (tick >> 32));

這樣可以保證99%不是一樣。

之後,我們就可以使用這個Random類的對象來産生随機數,這時候要用到Random.Next()方法。這個方法使用相當靈活,你甚至可以指定産生的随機數的上下限。

不指定上下限的使用如下: 

int iResult; 

iResult=ro.Next();

下面的代碼指定傳回小于100的随機數: 

int iResult; 

int iUp=100; 

iResult=ro.Next(iUp);

而下面這段代碼則指定傳回值必須在50-100的範圍之内: 

int iResult; 

int iUp=100; 

int iDown=50; 

iResult=ro.Next(iDown,iUp);

除了Random.Next()方法之外,Random類還提供了Random.NextDouble()方法産生一個範圍在0.0-1.0之間的随機的雙精度浮點數: 

double dResult; 

dResult=ro.NextDouble();

但是用Random類生成題号,會出現重複,特别是在數量較小的題目中要生成不重複的的題目是很難的。

參考了網上的一些方法,找到兩類解決方法,一類是通過随機種子入手,使每一次的随機種子不同,來保證不重複;第二類是使用一些資料結構和算法。

下面主要就第二類介紹幾個方法:

方法1:思想是用一個數組來儲存索引号,先随機生成一個數組位置,然後把随機抽取到的位置的索引号取出來,并把最後一個索引号複制到目前的數組位置,然後使随機數的上限減一,具體如:先把這100個數放在一個數組内,每次随機取一個位置(第一次是1-100,第二次是1-99,...),将該位置的數用最後的數代替。

int[] index = new int[15]; 

for (int i = 0; i < 15; i++) 

index = i; 

Random r = new Random(); 

//用來儲存随機生成的不重複的10個數 

int[] result = new int[10]; 

int site = 15;//設定上限 

int id; 

for (int j = 0; j < 10; j++) 

id = r.Next(1, site - 1); 

//在随機位置取出一個數,儲存到結果數組 

result[j] = index[id]; 

//最後一個數複制到目前位置 

index[id] = index[site - 1]; 

//位置的上限減少一 

site--; 

}

方法2:利用Hashtable。

Hashtable hashtable = new Hashtable(); 

Random rm = new Random(); 

int RmNum = 10; 

for (int i = 0; hashtable.Count < RmNum; i++) 

   int nValue = rm.Next(100); 

if (!hashtable.ContainsValue(nValue) && nValue != 0) 

    hashtable.Add(nValue, nValue); 

    Console.WriteLine(nValue.ToString()); 

}

方法3:遞歸,用它來檢測生成的随機數是否有重複,如果取出來的數字和已取得的數字有重複就重新随機擷取。

Random ra=new Random(unchecked((int)DateTime.Now.Ticks)); 

int[] arrNum=new int[10]; 

int tmp=0; 

int minValue=1; 

int maxValue=10; 

for (int i=0;i<10;i++) 

tmp=ra.Next(minValue,maxValue); //随機取數 

arrNum=getNum(arrNum,tmp,minValue,maxValue,ra); //取出值賦到數組中 

......... 

......... 

public int getNum(int[] arrNum,int tmp,int minValue,int maxValue,Random ra) 

int n=0; 

while (n<=arrNum.Length-1) 

if (arrNum[n]==tmp) //利用循環判斷是否有重複 

tmp=ra.Next(minValue,maxValue); //重新随機擷取。 

getNum(arrNum,tmp,minValue,maxValue,ra);//遞歸:如果取出來的數字和已取得的數字有重複就重新随機擷取。 

n++; 

return tmp; 

}