更新:2024/04/30

マージソート

1. マージソートの動作のイメージ図

大まかなマージソートの動作のイメージ図は次のようになります。


ただし、一気に全部分割しているのではなく、再帰的に分割されます。

はるか
はるか
ようは、分割と結合を再帰的に繰り返す。

2. マージソートのプログラム


def merge(A, p, q, r):
    print(f"merge(A,{p},{q},{r})")
    n1 = q - p + 1
    n2 = r - q
    L = [0] * n1
    R = [0] * n2
    
    for i in range(n1):
        L[i] = A[p + i]
    for j in range(n2):
        R[j] = A[q + j + 1]
    
    L.append(float('inf')) 
    R.append(float('inf'))
    
    i = 0
    j = 0
    for k in range(p, r + 1):
        if L[i] <= R[j]:
            A[k] = L[i]
            i += 1
        else:
            A[k] = R[j]
            j += 1

def merge_sort(A, p, r):
    if p < r:
        q = (p + r) // 2
    
        merge_sort(A, p, q)
        merge_sort(A, q + 1, r)
        merge(A, p, q, r)

A = [9,3,5,1,7]
print(A)
merge_sort(A, 0, len(A) - 1)
print(A)

はるか
はるか
マージソートのpythonプログラム。

ふゅか
ふゅか
プログラムはmergeとmerge_sort主に分かれています!

2.1. merge_sort関数

merge_sort 関数はリスト A を再帰的に分割していく役割を持っています。具体的には、リストの中間点 q を見つけ、それを境にリストを分け、それぞれに対してさらに merge_sort を適用します。最終的には分割されたリストが十分小さくなった時点(配列の長さが1以下)で、merge 関数によってソートしながら結合されます。

2.2. merge関数

merge 関数は、merge_sort から分割されたリストを受け取り(実際はリストとその添え字を受け取る)、それらをソートしながら一つのリストに結合する役割を果たします。この関数では、二つの配列 L (左のリスト) と R (右のリスト) を使用し、それぞれに対して番兵として無限大の値 float('inf') を配列の末尾に追加します。インデックス ij をそれぞれ LR の先頭に置き、小さい方の要素から順に元の配列 A にコピーしていきます。

3. 実際に動作を確認する。

ふゅか
ふゅか
配列A = [9,3,5,1,7]のマージソートの動作を見てきましょう!

3.1. merge(A,0,0,1)

初期条件として、L=[9,$\infty$],R=[3,$\infty$]、(i,j)=(0,0)、kの値は0≤k≤1となります。

[1]k=0、(i,j)=(0,0)の場合

L[0]>R[0]となるので、L[i] <= R[j]はfalseである。

したがって、A[0]=R[0]=3、j=1となる。(else節)

[2]k=1、(i,j)=(0,1)の場合

L[0]<R[1]となるので、L[i] <= R[j]はtrueである。

したがって、A[1]=L[0]=9、i=1となる。(if節)

したがって、Aの0から1は[3,9]となり図のようになる。

3.2. merge(A,0,1,2)

merge(A,0,0,1)により、左の[9,3]の部分は[3,9]になっている。

初期条件として、L=[3,9,$\infty$],R=[5,$\infty$]、(i,j)=(0,0)、kの値は0≤k≤2となります。

[1]k=0、(i,j)=(0,0)の場合

L[0]<R[0]となるので、L[i] <= R[j]はtrueである。

したがって、A[0]=L[0]=3、i=1となる。(if節)

[2]k=1、(i,j)=(1,0)の場合

L[1]>R[0]となるので、L[i] <= R[j]はfalseである。

したがって、A[1]=R[0]=5、j=1となる。(else節)

[3]k=2、(i,j)=(1,1)の場合

L[1]<R[1]となるので、L[i] <= R[j]はtrueである。

したがって、A[2]=L[1]=9、i=2となる。(if節)

したがって、Aの0から2は[3,5,9]となり図のようになる。

3.3. merge(A,3,3,4)

 

初期条件として、L=[1,$\infty$],R=[7,$\infty$]、(i,j)=(0,0)、kの値は3≤k≤4となります。

[1]k=3、(i,j)=(0,0)の場合

L[0]<R[0]となるので、L[i] <= R[j]はtrueである。

したがって、A[3]=L[0]=1、i=1となる。(if節)

[2]k=4、(i,j)=(1,0)の場合

L[1]>R[0]となるので、L[i] <= R[j]はfalseである。

したがって、A[4]=L[0]=7、j=1となる。(else節)

したがって、Aの3から4は[1,7]となり図のようになる。

3.4. merge(A,0,2,4)

初期条件として、L=[3,5,9$\infty$],R=[1,7,$\infty$]、(i,j)=(0,0)、kの値は0≤k≤4となります。

[1]k=0、(i,j)=(0,0)の場合

L[0]>R[0]となるので、L[i] <= R[j]はfalseである。

したがって、A[0]=R[0]=1、j=1となる。(else節)

[2]k=1、(i,j)=(0,1)の場合

L[0]<R[1]となるので、L[i] <= R[j]はtrueである。

したがって、A[1]=L[0]=3、i=1となる。(if節)

[3]k=2、(i,j)=(1,1)の場合

L[1]<R[1]となるので、L[i] <= R[j]はtrueである。

したがって、A[2]=L[1]=5、i=2となる。(if節)

[4]k=3、(i,j)=(2,1)の場合

L[2]>R[1]となるので、L[i] <= R[j]はfalseである。

したがって、A[3]=R[1]=7、j=2となる。(else節)

[5]k=4、(i,j)=(2,2)の場合

L[2]<R[2]となるので、L[i] <= R[j]はtrueである。

したがって、A[2]=L[2]=9、i=3となる。(if節)

したがってA=[1,3,5,7,9]となる。

PR