【C++】配列の内容をシャッフルするアルゴリズム(Fisher-Yates法)
このアルゴリズムは、与えられた配列の内容をシャッフルし、要素のランダムな順列を生成します。この手法は「Fisher-Yatesシャッフル(フィッシャー・イェーツのシャッフル)」として広く知られており、すべての順列が等しい確率で現れることが保証された効率的な方法です。
解き方のポイントは、配列の末尾のインデックスから開始し、0からそのインデックスまでの範囲でランダムに選んだ位置の要素と入れ替えていくことです。これにより、計算量O(n)で配列全体をシャッフルできます。
入力と出力
入力:
整数の配列:{1, 2, 3, 4, 5, 6, 7, 8}
出力:
シャッフル後の配列:3 4 7 2 6 1 5 8(※実行するたびに結果は異なります)
アルゴリズムの手順
randomArr(array, n)
入力: 配列と要素数
出力: シャッフルされた配列
Begin
for i := n - 1 down to 1, do
j := random number from 0 to i
swap arr[i] and arr[j]
done
End
処理の流れ
- i を n-1 から 1 まで減らしながら繰り返します。
- 各ループで、0 から i の範囲の乱数 j を生成します。
- arr[i] と arr[j] の内容を入れ替えます。
C++による実装例
#include <iostream>
#include<cstdlib>
#include <ctime>
using namespace std;
void display(int array[], int n) {
for (int i = 0; i < n; i++)
cout << array[i] << " ";
}
void randomArr ( int arr[], int n ) { // ランダムな配列要素を生成
srand (time(NULL)); // 時刻を使って異なるシード値を設定
for (int i = n-1; i > 0; i--) {
int j = rand() % (i+1); // 0からiの中からランダムにインデックスを選択
swap(arr[i], arr[j]); // 現在の要素とj番目の要素を入れ替え
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};
int n = 8;
randomArr(arr, n);
display(arr, n);
}
実行結果
4 7 8 2 6 3 5 1
まとめ
このシャッフルアルゴリズムは、配列の要素数をnとすると時間計算量O(n)、空間計算量O(1)で動作する非常に効率的な手法です。srand(time(NULL))によって実行ごとに異なるシード値を設定することで、毎回異なるシャッフル結果が得られる点も重要なポイントです。
-
C言語で配列の全要素の積を求めるプログラム
n個の要素を含む配列 arr[n] が与えられたとき、その配列内のすべての要素の積を求めることが課題となります。例えば、7つの要素からなる配列 arr[7] の場合、積は以下のように計算されます。例入力: arr[] = { 10, 20, 3, 4, 8 } 出力: 19200 説明: 10 × 20 × 3 × 4 × 8 = 19200 入力: arr[] = { 1, 2, 3, 4, 3, 2, 1 } 出力: 144解き方のアプローチ配列を入力として受け取る。配列のサイズを求める。配列を反復処理しながら、各要素を掛け合わせる。結果を表示する。アルゴリズム開始 関数 int pro
-
C言語で配列内の指定範囲の積(剰余演算)を求める方法
配列 A、範囲の左端 L、右端 R、そして素数 P を入力として与え、L から R までの範囲内にある要素の総乗(積)を P で割った余りを計算して出力するのが本記事の課題です。下図のように、配列の要素が並んでおり、左端の値 L は 2、右端の値 R は 6 です。プログラムはこの範囲内に含まれる要素の積を順次計算していきます。入出力例Input-: A[] = { 1, 2, 3, 4, 5, 6 } P = 29 L = 2 R = 6 Output-: 24 Input-: A[] = {1, 2, 3, 4, 5, 6}, L = 2 R = 5 P = 113