マージソート
マージソートは、もっとも高速なソートアルゴリズムのひとつです。実際の開発現場でも、マージソートをベースにした実装が広く使われています。これまでに、バブルソートや選択ソートなど、計算量が のアルゴリズムを見てきましたが、マージソートはそれらの二乗時間アルゴリズムよりもはるかに高速で、計算量は になります。

マージソートは、分割統治法(divide-and-conquer)を用いたアルゴリズムで、配列を再帰的に部分的にソートしてから、それらをマージして最終的なソートを完成させます。このアルゴリズムの要となるのは、2 つのソート済み配列を効率よく 1 つのソートされた配列に統合(マージ)する処理です。マージソートの実行過程では、まず配列を 2 つに分割し、それぞれを再帰的にソートした後、それら 2 つのソート済み配列をひとつにマージします:
def merge(a, b):
i, j, res = 0, 0, [] # a と b のインデックス、および結果を格納する配列
while i < len(a) or j < len(b): # まだ要素が残っている間
ai = a[i] if i < len(a) else float('inf')
bj = b[j] if j < len(b) else float('inf')
if ai < bj: # a[i] < b[j] の場合は a[i] を採用
res.append(ai) # 結果に a[i] を追加
i += 1 # 次の要素へ
else: # a[i] >= b[j] の場合は b[j] を採用
res.append(bj) # 結果に b[j] を追加
j += 1 # 次の要素へ
return res
def merge_sort(a):
if len(a) <= 1: # ソートする要素がないとき
return a # 配列をそのまま返す
l = merge_sort(a[: len(a) // 2]) # 左側をソート
r = merge_sort(a[len(a) // 2:]) # 右側をソート
return merge(l, r)
各ステージでは、配列を取り出して 2 つに分割し、それぞれをソートしてから、その結果を新しい配列としてマージします。これまで扱ってきたアルゴリズムはすべて元の配列を “in place” で変更していました(新しい配列を作らずに要素を並び替えていました)が、マージソートは各ステップで新しい配列を作ります。マージソートで in-place ソートを実現するのはとても難しいのですが、なぜだと思いますか?
では、実際にいくつかの配列を例にアルゴリズムをシミュレーションしてみましょう:
[4, 1, -1, 0, 2, 8]
merge_sort([4, 1, -1, 0, 2, 8])
:merge_sort([4, 1, -1])
merge_sort([0, 2, 8])
merge_sort([4, 1, -1])
:merge_sort([4])
→ return[4]
merge_sort([1, -1])
merge_sort([1, -1])
:merge_sort([1])
→ return[1]
merge_sort([-1])
→ return[-1]
- Back to
merge_sort([1, -1])
→ return[-1, 1]
- Back to
merge_sort([4, 1, -1])
→ return[-1, 1, 4]
merge_sort([0, 2, 8])
:merge_sort([0])
→ return[0]
merge_sort([2, 8])
merge_sort([2, 8])
:merge_sort([2])
→ return[2]
merge_sort([8])
→ return[8]
- Back to
merge_sort([2, 8])
→ return[2, 8]
- Back to
merge_sort([0, 2, 8])
→ return[0, 2, 8]
- Back to
merge_sort([4, 1, -1, 0, 2, 8])
→ return[-1, 0, 1, 2, 4, 8]
課題
与えられた
n
個の整数からなる配列を、マージソートを用いて降順に並び替えてください。 入力
最初の行には整数
n
(1 ≤ n ≤ 100 000)が与えられます。次の行には
n
個の整数 ( ≤ ≤ ) が空白区切りで与えられ、これが初期の配列を表します。 出力
降順に並び替えた
n
個の整数を空白区切りで表示してください。 例
入力 | 出力 |
4
7 4 9 1 | 9 7 4 1 |
5
-4 8 2 -3 6 | 8 6 2 -3 -4 |
Constraints
Time limit: 5 seconds
Memory limit: 512 MB
Output limit: 10 MB