歸併排序的簡單理解

程式設計師翔仔發表於2022-06-24

詳細描述

歸併排序的基本思想是,將已有序的子序列合併,可以得到有序的完整序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併

歸併排序詳細的執行步驟如下:

  1. 申請空間,使其大小為兩個已經排序序列之和,該空間用來存放合併後的序列;
  2. 設定兩個指標,最初位置分別為兩個已經排序序列的起始位置;
  3. 比較兩個指標所指向的元素,選擇相對小的元素放入到合併空間,並移動指標到下一位置;
  4. 重複步驟 3 直到某一指標超出序列尾。

演算法圖解

歸併排序

問題解疑

歸併排序和快速排序比較怎麼樣?

歸併排序的比較次數小於快速排序的比較次數,移動次數一般多於快速排序的移動次數。

歸併排序的應用在什麼場景?

歸併排序速度僅次於快速排序,為穩定排序演算法,一般用於對總體無序,但是各子項相對有序的序列。

歸併排序的時間複雜度是多少?

每次合併操作的平均時間複雜度為 \(O(n)\),而完全二叉樹的深度為 \(\log_2n\),總的平均時間複雜度為 \(O(n \log n)\)

並且,歸併排序的最好、最壞、平均時間複雜度均為 \(O(n \log n)\)

程式碼實現

package cn.fatedeity.algorithm.sort;

/**
 * 歸併排序演算法
 */
public class MergeSort {
    private static void merge(int[] numbers, int low, int mid, int high) {
        int i = low;
        int j = mid + 1;
        int[] newNumbers = new int[high - low + 1];
        int k = 0;

        while (i <= mid && j <= high) {
            if (numbers[i] < numbers[j]) {
                newNumbers[k++] = numbers[i++];
            } else if (numbers[i] > numbers[j]) {
                newNumbers[k++] = numbers[j++];
            } else {
                newNumbers[k++] = numbers[i++];
                newNumbers[k++] = numbers[j++];
            }
        }
        while (i <= mid) {
            newNumbers[k++] = numbers[i++];
        }
        while (j <= high) {
            newNumbers[k++] = numbers[j++];
        }

        if (high + 1 - low >= 0) {
            System.arraycopy(newNumbers, 0, numbers, low, high + 1 - low);
        }
    }

    private static int[] sort(int[] numbers, int low, int high) {
        if (low < high) {
            int mid = (low + high) >> 1;
            sort(numbers, low, mid);
            sort(numbers, mid + 1, high);
            merge(numbers, low, mid, high);
        }
        return numbers;
    }

    public static int[] sort(int[] numbers) {
        return sort(numbers, 0, numbers.length - 1);
    }
}

相關文章