フィッシャー–イェーツのシャッフルは、与えられた要素から
ランダムな
順列(並べ替え)を生成する
アルゴリズムです。この
アルゴリズムは、
ロナルド・フィッシャーとフランク・イェーツによって開発され、
ドナルド・クヌースによって「クヌースのシャッフル」としても知られています。
アルゴリズムの特長
公平性: 全ての可能な
順列が等しい確率で生成されます。
偏りがないため、公正な
ランダムな並べ替えが必要な場面に適しています。
効率性: 改良された
アルゴリズムは、要素数に比例した処理時間で実行され、追加のメモリ領域を必要としません。
アルゴリズムの流れ(改良版)
改良版のフィッシャー–イェーツのシャッフルは、コンピュータでの実装を想定しています。要素数nの
配列をシャッフルする手順は以下の通りです。
1.
配列の最後の要素から順に、要素番号`i`を減らしながらループを繰り返します(i = n-1, n-2, ..., 1)。
2. `i`番目の要素と、0から`i`までの間の
ランダムな要素番号`j`の要素を入れ替えます。
この操作を繰り返すことで、
配列の要素が
ランダムに並び替えられます。計算量はO(n)と非常に効率的です。
オリジナル版との違い
オリジナル版では、残りの要素の中から
ランダムに要素を選択していました。これは、残りの要素数を数える必要があり、計算量がO(n²)となっていました。改良版では、最後の要素との交換を行うことで、この余分な計算を省いています。
サットロのアルゴリズム
サットロの
アルゴリズムは、フィッシャー–イェーツのシャッフルを拡張した
アルゴリズムで、長さnの円
順列(環状に並んだ
順列)を生成します。改良版と異なるのは、
ランダムに選択する要素番号`j`の範囲が`0`から`i-1`までの間である点です。
「取り出し」版のアルゴリズム
「取り出し」版は、別途シャッフル後の
配列を用意し、元の
配列から要素を取り出して新しい
配列に配置していく方法です。メモリ使用量は増えますが、計算速度をわずかに向上させる可能性があります。特に、元の
配列の要素数が事前に不明な場合にも有効です。
実装上の注意点と偏りの可能性
フィッシャー–イェーツのシャッフルを実装する際には、以下の点に注意する必要があります。
乱数の質: 真に
ランダムまたは高品質な疑似乱数を使用する必要があります。低品質な乱数を使うと、生成される
順列に
偏りが生じます。
剰余の偏り: 乱数の範囲を絞る際に
剰余演算を使うと、
偏りが生じる可能性があります。適切な手法で範囲を絞る必要があります。
インデックスの範囲: ランダムに選択するインデックスの範囲を間違えると、サットロの
アルゴリズムになってしまったり、他の
偏りが生じたりします。
疑似乱数生成器の特性: 疑似乱数生成器の初期値、シード値、周期などに注意が必要です。生成できる
順列の数が少ないと、
偏りが生じます。
他のシャッフルアルゴリズムとの比較
フィッシャー–イェーツのシャッフルは、時間計算量と空間計算量の両面で非常に効率的です。他のシャッフル
アルゴリズム(例えば、
ランダムな数値を付与して
ソートする方法)と比較しても、その優位性は変わりません。
しかし、
ソートを用いた方法は並列処理に向いているという利点があります。一方、
ランダムな比較を行う
ソートアルゴリズムは、結果に強い
偏りが生じ、極めて非効率的になる可能性があるため注意が必要です。
結論
フィッシャー–イェーツのシャッフルは、公平で効率的な
ランダム順列生成
アルゴリズムです。しかし、実装の際には乱数の質やインデックスの範囲などに注意し、
偏りが生じないように注意深く実装する必要があります。様々な派生
アルゴリズムが存在し、それぞれの用途に最適な
アルゴリズムを選択することが重要です。