試験問題を自動的に生成できる試験システムを構築する場合、繰り返しのない一連の質問をランダムに生成する必要があることがよくあります。.net Framework には、乱数の生成に特に使用されるクラス System.Random が用意されています。
乱数に関しては、コンピューターが完全に乱数を生成することが不可能であることは誰もが知っています、いわゆる乱数生成器は、事前に選択されたランダムシードに対して特定のアルゴリズムを使用して複雑な演算を実行し、生成された結果を使用して近似します。完全に乱数のシミュレーションは擬似乱数と呼ばれます。擬似乱数は、有限の数値セットから等しい確率で選択されます。選択される数値は完全にランダムではありませんが、実用的な目的には十分なランダムです。擬似乱数の選択はランダム シードから始まるため、毎回取得される擬似乱数が十分に「ランダム」であることを保証するためには、ランダム シードの選択が非常に重要です。乱数シードが同じであれば、同じ乱数発生器で生成される乱数も同じになります。一般に、システム時間に関連するパラメーターを乱数シードとして使用します。これは、.net Framework の乱数ジェネレーターで使用されるデフォルトの方法でもあります。
乱数生成器は 2 つの方法で初期化できます:
最初の方法はランダム シードを指定せず、システムは現在時刻をランダム シードとして自動的に選択します:
Random ro = new Random();
2 番目の方法は次のことができます。ランダムシードとして Int 型パラメータを指定します:
int iSeed=10;
Random ro = new Random(10);
long tiny = 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 クラスには、0.0 ~ 1.0 の範囲でランダムな倍精度浮動小数点数を生成する Random.NextDouble() メソッドも用意されています。
double dResult;
dResult=ro. NextDouble();
ただし、Randomクラスを使って質問番号を生成すると重複が発生するため、特に質問数が少ない場合は重複しない質問を生成することが難しいのでいくつかのメソッドを参考にさせていただきます。インターネット上では 2 つのカテゴリが含まれます。1 つ目のタイプはランダム シードから始まり、重複がないように各ランダム シードが異なります。2 つ目のタイプはいくつかのデータ構造とアルゴリズムを使用します。以下では、主に 2 番目のカテゴリのいくつかの方法を紹介します。
方法 1: アイデアは、配列を使用してインデックス番号を保存し、最初に配列の位置をランダムに生成し、次にこの位置のインデックス番号を取り出し、最後のインデックス番号を現在の配列位置にコピーしてから、乱数の上限は 1 ずつ減ります。具体的には、まずこれら 100 個の数値を配列に入れ、毎回ランダムに位置を選択します (1 回目は 1 ~ 100、2 回目は 1 ~ 99、...)。位置を変更します。番号は最後の番号に置き換えられます。
int[]index = new int[15];
for (int i = 0; i index = i;
Random r = new Random();
//ランダム生成を保存するために使用されます10 個の非繰り返し数値
int[] result = new int[10];
int site = 15;//下限を設定します
int id;
for (int j = 0; j {
id = r.Next(1, site - 1);
//ランダムな位置の数値を取り出し、結果配列に保存
result[j] =index[id];
//最後の数値をコピー現在位置へ
index[id] =index[site - 1];
//位置の下限を1つ減らす
site--;
}
方法2:Hashtableを使う。 [NextPage]
ハッシュテーブル hashtable = new Hashtable();
ランダム 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:再帰、生成した乱数が重複しているかどうかを検出するために使用し、取り出した数値がすでに取得した数値と重複している場合は、再度ランダムに取得します。
ランダム 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 {
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;
}