C#で重複のない乱数の生成(Visual Studio)

  • このエントリーをはてなブックマークに追加

スポンサーリンク

※サイト運営にサーバーは必須です※
~このサイトもエックスサーバーを使用しています~

はじめに

この記事では、Visual Studio2015でダブりのない乱数をc#で作る方法を紹介する。

ついでに、生成した乱数をテキストファイルに出力する機能もついている

考え方

乱数のシャッフルのされ方には歴史がある。

Wiki:フィッシャー – イェーツのシャッフル

は非常に参考になる。

Wikiでは、フィッシャー – イェーツ(Fisher-Yate)とダステンフェルドのアルゴリズムを区別して扱っている。フィッシャー – イェーツ(Fisher-Yate)が当初考えた方法だと計算量がO(n2)だが、ダステンフェルドのアルゴリズムでは、O(n)と少なく済む。

※多くのサイトで、ダステンフェルドのアルゴリズムのことをFisher-Yate 法と呼んでいる。理由はよくわからないが、偏りのない乱数をまじめに考えた最初期の人がフィッシャーとイェーツだからだろう。

この記事でも、これらの考えを踏まえてコードを組んだ。

まず、1~10までの重複のない乱数を作りたいと考える。

その場合、10個の数字を入れる箱(配列)を用意する。そして、1番目の箱に1を、2番目の箱には2を……10番目の箱には10を入れる。

次に、1番目の箱を1~10番目の箱のどれかと交換する(自分と交換した場合、数字は変わらない)。その次は2番目の箱を2~10番目の箱のどれかと交換する。……9番目の箱は9~10番目の箱のどれかと交換する。

10番目の箱は、交換操作をしても、自分と交換するしかないので意味がない。そのため、この最後の交換操作は省略されているコードも世の中にはある。このサイトで紹介するコードは、交換操作の後に、交換して得た数字を記録している。その関係上、最後の(無意味な)交換操作も行っている。

この手の手法を紹介しているサイトの多くは、1番目でなく10番目からスタートしていることが多い。つまり、配列の末尾に交換操作が終わった数字を後ろに退避している。(最初にこの手法を考えた人は、先頭でなく末尾からスタートして考えたのだろうか?)。

本質的には、先頭から考えても、末尾から考えても結果は同じである。末尾から考えると、発生させる乱数の最大の数字と、残っている配列の数が一致するので、数字の管理が楽になるというメリットがある。

※このサイトでは、先頭から考えている。そのため、乱数生成の部分は、

と書いている。

末尾から考えると、

とすっきり書けるようになる。

先頭から考えているか末尾から考えているかは、交換操作を行っているループ文(for文やwhile文など)を制御している変数(例えばi)にインクリメント演算子(i++)がついているかデクリメント演算子(i--)が付いているかで判断できる。インクリメントの場合は先頭から考えており、デクリメントの場合は末尾から考えている。

このサイトのコードは、先頭から交換して考えている。末尾から考えると、交換操作の後に、交換して得た数字を記録する際に、少し面倒(r_arr[i]の部分をr_arr[r_num-i-1]にしないといけない)。

また、このサイトで紹介するコードを少しいじくれば、指定した数の乱数を得ることができる。例えば、1~10000までの乱数を考えるが、必要な乱数は最初の10個だけという場合に、交換操作を途中で打ち切れるようになっている (変数r_triで指定できる) 。末尾から考えると、この打ち切り操作を指定する部分で少し頭がこんがらがる。

コード

まず、Visual Studio 2015を立ち上げる。
左上にある「ファイル」→「新規作成」→「プロジェクト」から「コンソールアプリケーション」を選択。

名前は好きに指定(ここでは「r_test」としている)

ソースコードは以下のようになる。

 

は、ファイルの出力に必要。

発生させる乱数の最大値の指定、

 

発生させる乱数の最小値の指定、

用意する箱(配列の要素)の数

+1される理由は説明しなくても問題ないかな?(例えば、10~20の間に含まれる数字は10個でなく11個)

 

生成する乱数の数。途中で交換操作を打ち切って問題ない場合に指定。

 

配列の宣言

 

ファイルの名前は条件に合わせて自動生成される。(例えば、min15_max100_trial86.txtと生成される)

 

で初期条件をテキストファイルに記録。

 

で、用意した配列に数字を入れている。

 

乱数生成の準備

 

 

箱の交換操作(シャッフル)に対応。int temp = r_arr[i];で交換操作前のi番目の箱に入っている数字を覚えている。r_arr[i] = r_arr[r];でi番目とr番目の箱を交換。r_arr[r] = temp;でi番目の箱に入っていた数字をr番目の箱の箱に入れている。

最後にファイルを閉じておしまい。

 

このコードを実行するには「Ctrl+F5」を押す (ここではDebugモードで行っている) 。

コマンドプロンプト立ち上がるが、エンターを押す。

コマンドプロンプトが消えたら、「保存したファイル(ここではr_terst)」→「保存したファイル(ここではr_terst)」→「bin」→「Debug」の中にテキストファイルが生成される。
(紹介しているコードをそのまま実行するとmin15_max100_trial86.txt)

テキストファイルの中身はこんな感じになる。

~Webサイトを自分で作ってみませんか?~

Webサイトを運営するにはサーバーが必須です。
このサイトは、エックスサーバー のサーバーを使用しています。
エックスサーバーは無料で10日間お試しができます。

     

コメント

コメントを残す

*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)