マージソート

ソートのアルゴリズムのひとつ

マージソートは、ソートアルゴリズムで、既に整列してある複数個の列を1個の列にマージする際に、小さいものから先に新しい列に並べれば、新しい列も整列されている、というボトムアップの分割統治法による。大きい列を多数の列に分割し、そのそれぞれをマージする作業は並列化できる。

マージソート
クラス ソート
データ構造 配列
最悪計算時間
最良計算時間

typical,

natural variant
平均計算時間
最悪空間計算量 外部記憶
マージソートの様子

nO(n log n)使O(n)[1]

[1]

1945[2]

アルゴリズム

編集



(一)

(二)1213

(三)1

12使

322

[1]

(一)

(二)13

(三)

142使2使2

222

1The Art of Computer Programming§5.4

実装例

編集
#include <stdio.h>
void merge(int A[], int B[], int left, int mid, int right) {
    int i = left;
    int j = mid;
    int k = 0;
    int l;
    while (i < mid && j < right) {
        if (A[i] <= A[j]) {
            B[k++] = A[i++];
        } else {
            B[k++] = A[j++];
        }
    }
    if (i == mid) { /* i側のAをBに移動し尽くしたので、j側も順番にBに入れていく */
        while (j < right) {
            B[k++] = A[j++];
        }
    } else {
        while (i < mid) { /* j側のAをBに移動し尽くしたので、i側も順番にBに入れていく */
            B[k++] = A[i++];
        }
    }
    for (l = 0; l < k; l++) {
        A[left + l] = B[l];
    }
}
void merge_sort(int A[], int B[], int left, int right) {
    int mid;
    if (left == right || left == right - 1) { return; }
    mid = (left + right) / 2;
    merge_sort(A, B, left, mid);
    merge_sort(A, B, mid, right);
    merge(A, B, left, mid, right);
}
int main(void) {
    int a[10] = {8,4,7,2,1,3,5,6,9,10};
    int b[10] = {0};
    const int n = 10;
    int i;
    merge_sort(a, b, 0, n);
    for (i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");
}
def mergesort lst
    return _mergesort_ lst.dup  # 副作用で配列が壊れるので、複製を渡す
end

def _mergesort_ lst
    if (len = lst.size) <= 1 then
        return lst
    end

    # pop メソッドの返す値と副作用の両方を利用して、lst を二分する
    lst2 = lst.pop(len >> 1)

    return _merge_(_mergesort_(lst), _mergesort_(lst2))
end

def _merge_ lst1, lst2
    len1, len2 = lst1.size, lst2.size
    result = Array.new(len1 + len2)
    a, b = lst1[0], lst2[0]
    i, j, k = 0, 0, 0
    loop {
        if a <= b then
            result[i] = a
            i += 1 ; j += 1
            break unless j < len1
            a = lst1[j]
        else
            result[i] = b
            i += 1 ; k += 1
            break unless k < len2
            b = lst2[k]
        end
    }
    while j < len1 do
        result[i] = lst1[j]
        i += 1 ; j += 1
    end
    while k < len2 do
        result[i] = lst2[k]
        i += 1 ; k += 1
    end
    return result
end

Haskell

編集

(※ Haskellのリストは「長さを測って半分ずつに分ける」という操作には適さないため、要素を1個ずつ振り分ける関数を使っている。この実装では安定ではない)

mergesort :: Ord t => [t] -> [t]
mergesort lst = case lst of
   []  -> lst
   [_] -> lst
   _   -> merge (mergesort a) (mergesort b)
      where
         (a, b)  =  split lst

         merge []  []   =  []
         merge xxs []   =  xxs
         merge []  yys  =  yys
         merge xxs@(x : xs) yys@(y : ys)
            | x < y      =  x : (merge xs yys)
            | otherwise  =  y : (merge xxs ys)

         split []         =  ([], [])
         split ~(x : xs)  =  (x : zs, ys)
            where
               (ys, zs) = split xs

Scheme

編集
;; use-modules は 処理系 Guile 固有の機能である。
;; SRFI 機能を使うための仕組み処理系に依る。
(use-modules (srfi srfi-1 )) ; split-at
(use-modules (srfi srfi-11)) ; let-values

(define (merge left-half right-half)
  (let loop ((ls left-half) (rs right-half) (result (list)))
    (cond
      ((null? rs) (append (reverse result) ls))
      ((null? ls) (append (reverse result) rs))
      (else
        (let ((l (car ls)) (r (car rs)))
          (if (<= l r)
            (loop (cdr ls) rs (cons l result))
            (loop ls (cdr rs) (cons r result))))))))

(define (merge-sort xs)
  (cond
    ((null?      xs ) xs)
    ((null? (cdr xs)) xs)
    (else
      (let-values
        (((left-half right-half)
          (split-at xs (quotient (length xs) 2))))
        (merge
          (merge-sort left-half)
          (merge-sort right-half))))))

アルゴリズムの動作例

編集

: 8 4 3 7 6 5 2 1

(一)
8 4 3 7 | 6 5 2 1

(二)
8 4 | 3 7 | 6 5 | 2 1

(三)2
4 8 | 3 7 | 5 6 | 1 2

(四)222
3 4 7 8 | 1 2 5 6

(五)2
1 2 3 4 5 6 7 8

脚注

編集
  1. ^ a b c 奥村晴彦『C言語による最新アルゴリズム事典』技術評論社、1991年、267頁。ISBN 4-87408-414-1 
  2. ^ Knuth, Donald (1998). “Section 5.2.4: Sorting by Merging”. Sorting and Searching. The Art of Computer Programming. 3 (2nd ed.). Addison-Wesley. pp. 158. ISBN 0-201-89685-0 

関連項目

編集

外部リンク

編集