選択ソート(Selection Sort)
選択ソートとは
ソートアルゴリズムの中でも、最も基本的なアルゴリズムの一つです。配列の中から最小値や最大値を探して、先頭や最後尾と入れ替えながらソートしていきます。
他のソートには計算量が \(O(nlogn)\) のものもありますが、選択ソートの計算量は \(O(n^2)\) となっています。
しかし、アルゴリズムが簡単なので、遅くても使われることがあります。
通常の選択ソートは安定ソート(Stable Sort) ではありませんが、アルゴリズムの一部を変更することで安定ソートにすることができます。
アルゴリズム
以下のように最小の要素を見つけて、配列の先頭と入れ替えることを続けます。
- \(i=0\) とする
- \(i\) 番目から配列の最後尾まで全ての要素を確認し、最小の要素と \(i\) 番目の要素を入れ替える
- \(i\) を 1 増やして、\(i\) が配列の長さ以上だったら終了。そうでなければ 2. に戻る
ここでの2.のように「最小の要素と\(i\)番目の要素を入れ替える」とすると安定ではないソート、「最小の要素を\(i\)番目の要素の前に挿入して、他を前に1つずつずらす」に変更すると安定ソートになります。
最小の要素をみつけるためには、以下のアルゴリズムを用いれば良いです。
- \(j=i\) とする
- \(i\) 番目から \(j\) 番目までで見つけた最小の要素とそのindexを覚えておき、\(j+1\) 番目がそれより小さいかどうかを比較する
- \(j\) を 1 増やして、\(j\) が配列の長さ以上だったら現在保持している最小の要素のindexを返して終了
- そうでなければ 2. に戻る
計算量
- \(O(n^2)\)
配列の要素数を n とすると、最小値を見つけて要素を交換するのに平均 n 回比較を行い、0 番目から n-1 番目までこれを繰り返すので、計算量は \(O(n^2)\) となります。(プログラム上では2重のループで記述できます。)
計算量の詳しい説明
比較回数は、\(i\)番目から配列の最後尾まで確認するために \(n-i-1\) 回必要です。また、この時の交換回数は 0 か 1 回です。
これが、\(i\) が \(0\) から \(n-1\) のときまで繰り返されるので、比較回数の総和は
$$ \sum_{i=0}^{n-1} (n-i-1) = \frac{n(n-1)}{2}$$
となります。また、交換回数の総和は多くても \(n-1\) 回。
以上から、オーダー記法を用いると、計算量は \(O(n^2)\) とわかります。
Pythonでのプログラム例
def selection_sort(arr): for i in range(len(arr)): min_value = arr[i] min_index = i for j in range(i, len(arr)): # ループで最小の要素を確認する if arr[j] < min_value: min_value = arr[j] min_index = j # 要素の入れ替え、arr[i],arr[min_index] = arr[min_index],arr[i] としてもよい tmp = arr[i] arr[i] = arr[min_index] arr[min_index] = tmp arr = [3,1,55,2,28,19,31,93,6] selection_sort(arr) print(arr) # 出力は[1, 2, 3, 6, 19, 28, 31, 55, 93]
(Colaboratory などで確認してみて下さい)
ディスカッション
コメント一覧
アルゴリズムの項でどちらも安定ソートと記載されていました。。
ありがとうございます。修正しておきました!