Javaでマージソート

Javaでのソートのマージ

1. 前書き

このチュートリアルでは、the Merge Sort algorithm and its implementation in Javaについて説明します。

マージソートは最も効率的なソート手法の1つであり、「分割統治」パラダイムに基づいています。

2. アルゴリズム

Merge sort is a “divide and conquer” algorithm wherein we first divide the problem into subproblems.サブ問題の解決策の準備ができたら、それらを組み合わせて問題の最終的な解決策を取得します。

これは、主な問題ではなく副問題に対処するため、再帰を使用して簡単に実装できるアルゴリズムの1つです。

このアルゴリズムは、次の2段階のプロセスとして説明できます。

  • Divide: In this step, we divide the input array into 2 halves、ピボットは配列の中点です。 このステップは、分割する半分の配列がなくなるまで、すべての半分の配列に対して再帰的に実行されます。

  • 下から上にConquer: In this step, we sort and merge the divided arraysし、ソートされた配列を取得します。

次の図は、サンプル配列\ {10、6、8、5、7、3、3、4}の完全なマージソートプロセスを示しています。

ダイアグラムを詳しく見ると、サイズが1になるまで、配列が再帰的に2つの半分に分割されていることがわかります。 サイズが1になると、マージプロセスが実行され、ソート中に配列のマージが開始されます。

image

3. 実装

実装の場合、パラメーターとしてwe’ll write a mergeSort function which takes in the input array and its length。 これは再帰関数になるため、ベース条件と再帰条件が必要です。

基本条件は、配列の長さが1であるかどうかをチェックし、そのまま戻ります。 残りのケースでは、再帰呼び出しが実行されます。

For the recursive case, we get the middle index and create two temporary arrays l[] and r[]。 次に、mergeSort関数が両方のサブ配列に対して再帰的に呼び出されます。

public static void mergeSort(int[] a, int n) {
    if (n < 2) {
        return;
    }
    int mid = n / 2;
    int[] l = new int[mid];
    int[] r = new int[n - mid];

    for (int i = 0; i < mid; i++) {
        l[i] = a[i];
    }
    for (int i = mid; i < n; i++) {
        r[i - mid] = a[i];
    }
    mergeSort(l, mid);
    mergeSort(r, n - mid);

    merge(a, l, r, mid, n - mid);
}

We then call the merge function which takes in the input and both the sub-arrays and the starting and end indices of both the sub arrays

merge関数は、両方のサブ配列の要素を1つずつ比較し、小さい方の要素を入力配列に配置します。

サブ配列の1つの終わりに達すると、他の配列の残りの要素が入力配列にコピーされ、最終的なソート済み配列が得られます。

public static void merge(
  int[] a, int[] l, int[] r, int left, int right) {

    int i = 0, j = 0, k = 0;
    while (i < left && j < right) {
        if (l[i] <= r[j]) {
            a[k++] = l[i++];
        }
        else {
            a[k++] = r[j++];
        }
    }
    while (i < left) {
        a[k++] = l[i++];
    }
    while (j < right) {
        a[k++] = r[j++];
    }
}

プログラムの単体テスト:

@Test
public void positiveTest() {
    int[] actual = { 5, 1, 6, 2, 3, 4 };
    int[] expected = { 1, 2, 3, 4, 5, 6 };
    MergeSort.mergeSort(actual, actual.length);
    assertArrayEquals(expected, actual);
}

4. 複雑

マージソートは再帰的なアルゴリズムであるため、時間の複雑さは次の再帰的な関係として表現できます。

T(n) = 2T(n/2) + O(n)

2T(n/2)はサブ配列のソートに必要な時間に対応し、O(n)は配列全体をマージするのに必要な時間に対応します。

解決すると、the time complexity will come to O(nLogn).

これは、最悪の場合、平均的な場合、および最良の場合に当てはまります。これは、配列を常に2つに分割してからマージするためです。

再帰呼び出しごとに一時配列を作成するため、アルゴリズムのスペースの複雑さはO(n)です。

5. 結論

このクイックチュートリアルでは、マージソートアルゴリズムの動作と、それをJavaで実装する方法について説明しました。

作業コード全体がover on GitHubで利用可能です。