マージソート

マージソートは、もっとも高速なソートアルゴリズムのひとつです。実際の開発現場でも、マージソートをベースにした実装が広く使われています。これまでに、バブルソートや選択ソートなど、計算量が のアルゴリズムを見てきましたが、マージソートはそれらの二乗時間アルゴリズムよりもはるかに高速で、計算量は になります。
Video preview
マージソートは、分割統治法(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]
  1. merge_sort([4, 1, -1, 0, 2, 8]):
    1. merge_sort([4, 1, -1])
    2. merge_sort([0, 2, 8])
  1. merge_sort([4, 1, -1]):
    1. merge_sort([4]) → return [4]
    2. merge_sort([1, -1])
  1. merge_sort([1, -1]):
    1. merge_sort([1]) → return [1]
    2. merge_sort([-1]) → return [-1]
  1. Back to merge_sort([1, -1]) → return [-1, 1]
  1. Back to merge_sort([4, 1, -1]) → return [-1, 1, 4]
  1. merge_sort([0, 2, 8]):
    1. merge_sort([0]) → return [0]
    2. merge_sort([2, 8])
  1. merge_sort([2, 8]):
    1. merge_sort([2]) → return [2]
    2. merge_sort([8]) → return [8]
  1. Back to merge_sort([2, 8]) → return [2, 8]
  1. Back to merge_sort([0, 2, 8]) → return [0, 2, 8]
  1. 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

To check your solution you need to sign in
Sign in to continue