首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現歸併排序算法:原理圖解與完整代碼

     編輯:Java 相關知識

算法思想

歸併排序是典型的分治法:

  1. 分解:將數組不斷二分,直到每個子數組只剩 1 個元素(天然有序)。
  2. 解決:將兩個有序子數組合併為一個有序數組(歸併操作)。
  3. 合併:自底向上逐層合併,最終得到完全有序數組。

時間複雜度:O(n log n)(最好/最壞/平均)。空間複雜度:O(n)(輔助數組)。穩定排序。

圖解過程

以數組 {3, 2, 4, 1} 為例:

分解階段:
{3, 2, 4, 1}
   /       \
{3, 2}    {4, 1}
 /  \      /  \
{3} {2}  {4} {1}

歸併階段:
{3} {2}  ->  {2, 3}
{4} {1}  ->  {1, 4}
{2, 3} {1, 4}  ->  {1, 2, 3, 4}

Java 完整實現

public class MergeSort {

    /** 入口方法 */
    public static void sort(int[] array) {
        if (array == null || array.length < 2) return;
        mergeSort(array, 0, array.length - 1);
    }

    /** 遞歸分解 */
    private static void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int mid = left + ((right - left) >> 1); // 防止溢出
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);
            merge(arr, left, mid, right);
        }
    }

    /** 合併兩個有序區間 [left, mid] 和 [mid+1, right] */
    private static void merge(int[] arr, int left, int mid, int right) {
        int[] temp = new int[right - left + 1];
        int i = left, j = mid + 1, k = 0;

        // 雙指針比較合併
        while (i <= mid && j <= right) {
            temp[k++] = (arr[i] <= arr[j]) ? arr[i++] : arr[j++]; // <= 保證穩定性
        }
        // 複製剩餘元素
        while (i <= mid) temp[k++] = arr[i++];
        while (j <= right) temp[k++] = arr[j++];

        // 寫回原數組
        System.arraycopy(temp, 0, arr, left, temp.length);
    }

    // 測試
    public static void main(String[] args) {
        int[] arr = {3, 2, 4, 1, 5, 0, -1, 8};
        System.out.println("排序前: " + Arrays.toString(arr));
        sort(arr);
        System.out.println("排序後: " + Arrays.toString(arr));
    }
}

關鍵點解析

細節說明
中點計算left + ((right - left) >> 1) 避免 (left+right)/2 整數溢出
穩定性合併時 arr[i] <= arr[j] 先取左邊元素,保證相等元素相對順序不變
輔助數組每次 merge 分配新數組,簡單但頻繁 GC;優化可在頂層分配一次傳遞複用
拷貝回寫System.arraycopy 為本地方法,比手寫循環快

優化版:自底向上迭代法(避免遞歸開銷)

public static void sortIterative(int[] arr) {
    int n = arr.length;
    int[] temp = new int[n];
    for (int width = 1; width < n; width <<= 1) { // 子數組寬度 1,2,4,8...
        for (int left = 0; left < n; left += (width << 1)) {
            int mid = Math.min(left + width - 1, n - 1);
            int right = Math.min(left + (width << 1) - 1, n - 1);
            if (mid < right) merge(arr, temp, left, mid, right);
        }
    }
}

private static void merge(int[] arr, int[] temp, int left, int mid, int right) {
    // 同遞歸版 merge 邏輯,但直接使用外部傳入的 temp
    // 合併後寫回 arr
}

應用場景與對比

算法時間複雜度空間複雜度穩定適用場景
歸併排序O(n log n)O(n)是外部排序、鏈表排序、需穩定性、數據近似有序
快速排序O(n log n) 平均O(log n)否通用內存排序、原地排序
堆排序O(n log n)O(1)否嵌入式、實時系統、保證最壞情況
TimSortO(n log n)O(n)是Java Arrays.sort(Object[])、Python sorted() 實際使用

總結

歸併排序以穩定、固定 O(n log n) 性能著稱,是外部排序和鏈表排序的首選。Java 中 Arrays.sort() 對對象數組使用 TimSort(歸併+插入優化),對基本類型使用雙軸快排。理解歸併核心邏輯有助於掌握分治思想、優化大數據排序及面試高頻考點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved