- ベストアンサー
公平なランダム
重複のないn個の配列を作成する、効率がよくて高速なランダム発生プログラムを探しています。 現在は下記のようなロジックを組んでいます。 1.n個の配列を用意(nはパラメータで与えられる) 2.配列に1からnまでの数値を昇順に格納 3.ランダムな値xを生成し、配列の1番目とx番目を交換 4.ランダムな値xを生成し、配列の2番目とx番目を交換 : : 5.ランダムな値xを生成し、配列のn番目とx番目を交換 この方法を越えるものはないでしょうか。 条件は、効率(公平性)がこれよりも高くて、速度が O(2n) を超えないことです。 最終的に配列の先頭20個程度の効率が高くなっていればよく、それ以降は多少偏りがあっても構いません。 ちなみに現在は、単純に x = rand(n); という方法で生成しており、初期化関数は使っていません。 よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
良くあるのは、 1.n個の配列を用意(nはパラメータで与えられる) 2.配列に1からnまでの数値を昇順に格納 3.配列にランダムな値xを格納 4.配列をxでソート 5.並べ替えられた1からnの数字を取り出し ですね。 高速なソートを行えば、早いハズ。 > 速度が O(2n) を超えないことです。 何のオーダーなのかわかりません。 交換の処理回数が2n、ランダムな値の生成回数が2n、評価の回数が2n、ボトルネックになるのをどの処理と定義するかによります。 -- > 最終的に配列の先頭20個程度の効率が高くなっていればよく、 20個以上は必要ないという事でしたら、棄却法のような方法が良いかも。 1.ランダムに1からnの範囲の数を生成。 2.既に格納されている値なら1へ。 3.格納数が20になるまで繰り返し。 nが十分大きければ、ほぼ20回で処理が終了するハズ。 逆に、nが21とかですと、なかなか決まりません。
その他の回答 (3)
- UKY
- ベストアンサー率50% (604/1207)
乱数が一様に分布し、乱数発生に掛かるコストは一定という仮定の元で、 1. 配列の要素を1~nでそれぞれ初期化する。 2. 1~nの乱数Rを取り出し、R番目とn番目の要素を入れ替える。 3. 1~n-1の乱数Rを取り出し、R番目とn-1番目の要素を入れ替える。 4. 1~n-2の乱数Rを取り出し、R番目とn-2番目の要素を入れ替える。 (中略) n. 1~2の乱数Rを取り出し、R番目と2番目の要素を入れ替える。 完全に公平で、オーダーは O(n) になります。 また、nの値がある程度大きければ、全ての要素を入れ替えずに6~7割入れ替えた時点で終わりにしてしまってもそれなりにランダムになっていると思います。 なお、上のアルゴリズムでは配列の後ろの方から値を入れ替えるようになっているので、必要に応じて適宜修正してください。
お礼
ありがとうございます。 俺の作ったロジックはある程度公平だったんですね。 よかったよかった。
- ymmasayan
- ベストアンサー率30% (2593/8599)
n個の間、データをダブらせないためには次のようにします。 1.1~nの乱数(x)を作り、xとnを交換します。 2・1~n-1の乱数(x)を作り、xとn-1を交換します。 これを繰り返していきます。 xが出力系列です。
お礼
ありがとうございます。 なんか難しくなってきましたね(^_^; これも試してみますね。
- ymmasayan
- ベストアンサー率30% (2593/8599)
大体いいと思いますが、同じデータが出てくるのは構わないのでしょうか。 これを防ぐ方法もありますが必要あれば言ってください。
お礼
ありがとうございます。 重複があったらダメです。 システムの都合上、データが壊れるんです(^_^; よろしくお願いします。
補足
ありがとうございます。 ランダムな数値をさらにソートするというのは面白い方法ですね。たしかに効率はよくなりそうですね。 ちなみにオーダーは、配列を1からnまで一通りの「生成、評価、交換」を行ったところで O(n) であるというつもりでした。 ちなみに棄却法は試したんですが、20番目以降のデータも「いちおーそれっぽく」入れ替わっている必要がある関係で、実行したらあっさりハングアップしました(笑)(いつかは返ってくるんでしょうけど(^_^;)