マージソートは、分割統治法(divide and conquer)を用いた効率的なソートアルゴリズムです。以下にマージソートの特徴と仕組みを解説します。
1. マージソートの基本概念
マージソートは以下の3つのステップで動作します:
- 分割(Divide): 配列を半分に分割します
- 統治(Conquer): 分割した各部分を再帰的にソートします
- 結合(Merge): ソートされた部分配列を結合して完全にソートされた配列を作ります
もう少しわかりやすく整理すると次のようになります。
マージソートは大きく「分割(Divide)」と「統治・マージ(Conquer & Merge)」の2つのフェーズに分けられ、それぞれが再帰的に処理されます。
- 分割(Divide)フェーズ:
- 配列を単一要素(長さ1)になるまで再帰的に分割していきます
- これは「分割→分割→分割…」と木構造のように下へ下へと進みます
- 単一要素になった時点で、その要素は「すでにソート済み」とみなされます
- 統治・マージ(Conquer & Merge)フェーズ:
- 単一要素になった後、各部分配列をマージ(結合)していきます
- マージする際に、2つのソート済み配列を比較しながら新しいソート済み配列を作ります
- これを再帰呼び出しから戻りながら繰り返し、最終的に完全にソートされた1つの配列になります
2. マージソートのアルゴリズム
関数 マージソート(配列):
もし 配列の長さ ≤ 1 なら:
配列を返す(すでにソート済みとみなす)
中間点 = 配列の長さ ÷ 2
左側 = マージソート(配列の前半)
右側 = マージソート(配列の後半)
結合(左側, 右側)を返す
関数 結合(左側配列, 右側配列):
結果配列 = 空の配列
左側インデックス = 0
右側インデックス = 0
while 左側インデックス < 左側配列の長さ かつ 右側インデックス < 右側配列の長さ:
if 左側配列[左側インデックス] <= 右側配列[右側インデックス]:
結果配列に左側配列[左側インデックス]を追加
左側インデックスを1増やす
else:
結果配列に右側配列[右側インデックス]を追加
右側インデックスを1増やす
残りの要素を結果配列に追加
結果配列を返す
より具体的な例は以下のとおりです。
3. マージソートの実装例(JavaScript)
より具体的な理解のために、JavaScriptでの実装例を示します:
function mergeSort(arr) {
// 配列の長さが1以下の場合はそのまま返す
if (arr.length <= 1) {
return arr;
}
// 配列を半分に分割
const middle = Math.floor(arr.length / 2);
const left = arr.slice(0, middle);
const right = arr.slice(middle);
// 分割した配列を再帰的にソート
return merge(
mergeSort(left),
mergeSort(right)
);
}
function merge(left, right) {
let result = [];
let leftIndex = 0;
let rightIndex = 0;
// 左右の配列を比較しながら小さい方から結果配列に追加
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
// 残りの要素を追加
return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));
}
4. マージソートのシミュレーション
5. マージソートの特徴
- 時間計算量: O(n log n) – これは配列のサイズに関係なく常に保証されます
- 空間計算量: O(n) – 追加のメモリ空間が必要です
- 安定性: 安定ソート(同じ値の要素の相対的な順序が保持される)
- 適用場合: 大規模データや連結リストのソートに適しています
6. マージソートの利点と欠点
6.1. 利点
- 常に O(n log n) の時間計算量を保証
- 安定ソートである
- 外部ソートに適している(全データをメモリに読み込まなくても処理可能)
6.2. 欠点
- 追加のメモリ空間が必要
- 小さな配列に対しては挿入ソートなどの単純なアルゴリズムの方が効率的な場合がある
マージソートはその安定性と予測可能な性能から、多くの言語の標準ライブラリでも採用されているソートアルゴリズムの一つです。大きなデータセットや連結リストのソートに特に有効です。