ソートアルゴリズムとは
データの集合を大小関係等の規則によって整列させるアルゴリズムを指します。プログラミングにおいてデータのソートは非常に重要で頻繁に使われます。そのため長い年月をかけて、様々なアルゴリズムが研究されています。
前述のとおりソートアルゴリズムは様々な種類がありますが、代表的なものからいくつかを紹介していこうと思います。紹介するソートアルゴリズムは以下の通りです。
ソートアルゴリズムの分類
ソートアルゴリズムはいくつかの方法で分類することができます。
安定ソート
安定ソートとは、同等なデータについて、ソート前の順序がソート後も保持されるソートアルゴリズムを指します。
例えば、氏名と年齢からなる以下のようなデータについて考えます。
ソート前のデータ
氏名 | 年齢 |
---|---|
山田 | 25 |
鈴木 | 30 |
佐藤 | 25 |
西村 | 20 |
年齢昇順でソートすると、「山田」「佐藤」の年齢が25で同じデータですが、ソート後の順序はどのようになるでしょうか。このような場合にソート前の順序「山田」「佐藤」の順で並ぶことが保証されるソートを、安定ソートと呼びます。
安定ソート後のデータ
氏名 | 年齢 |
---|---|
西村 | 20 |
山田 | 25 |
佐藤 | 25 |
鈴木 | 30 |
内部ソート/外部ソート
ソートを実行する際に、ソート対象のデータの格納領域以外に、O(1) か O(log n) の領域しか必要としないソートを内部ソートと呼びます。
内部ソートの例として、バブルソートがあります。バブルソートは要素の交換を繰り返しながらソートを行います。必要となるデータ領域は、格納領域のほかには、交換の際の O(1) のみです。よって内部ソートに分類されます。
同じく内部ソートの例として、クイックソートが挙げられます。クイックソートは再帰的な呼び出しを用います。そのため O(log n) の外部領域を必要としますが、これは分類上、内部ソートとされます。
外部ソートは上記以外の例、すなわちソート対象のデータ格納領域以外に O(n) 以上の外部領域を必要とするソートアルゴリズムを指します。例えばマージソートが一例です。マージソートはマージの際に、最大 n/2 の外部領域を必要とします。つまり、O(n) の外部領域を必要とするため、外部ソートとなります。
計算量
ソート対象のデータ数 n を基準とした計算量でアルゴリズムを分類できます。要は n が増加したときに、どれだけ実行時間が増えるかの目安です。計算量は、最悪と平均をそれぞれ考慮する必要があります。
計算量が小さいほうが、基本的には性能のよいアルゴリズムとなります。これはソート以外のアルゴリズムでも当てはまるものです。主だった、計算量の大小関係は以下の通りです。
O(1) < O(log n) < O(n) < O(n log n) < O(n1.5) < O(n2)
一般的にソートアルゴリズムでは、O(n log n) が高速で、O(n2) のアルゴリズムは低速とされます。あとは条件次第で使い分けます。
アルゴリズム一覧
名称 | 計算時間 | 内部/外部 | 安定/不安定 | 備考 |
---|---|---|---|---|
バブルソート | O(n2) | 内部ソート | 安定 | 遅い |
選択ソート | O(n2) | 内部ソート | 安定 | 交換回数がバブルソートより少ない。 |
挿入ソート | O(n2) | 内部ソート | 安定 | ほぼソート済や少ないデータに対しては高速 |
シェルソート | O(n2) ※ | 内部ソート | 不安定 | ※最悪の場合 間隔 h の取り方次第でO(n2)よりは高速になる。 |
クイックソート | O(n log n) | 内部ソート | 不安定 | 実用上最速とされる。ピボットの取り方がまずいと最悪計算量 O(n2) に陥る。 |
マージソート | O(n log n) | 外部ソート | 安定 | 安定かつ高速だがメモリを使用する。 |
ヒープソート | O(n log n) | 内部ソート | 不安定 | |
バケットソート | O(n) | 外部ソート | 安定 | キーの取りうる値がm種類しかなく、mがあまり大きくないという前提が必要。強い制限があるが、非常に高速。 |
基数ソート | O(n) | 外部ソート | 安定 | キーの取りうる値がm種類しかなく、最大値と最小値がはっきりしているという前提が必要。キーの桁数分バケットソートを繰り返す。 |