归并排序 Java 实现(递归 + 非递归)

目录

[1. 递归版归并排序(最常用)](#1. 递归版归并排序(最常用))

[2. 非递归版归并排序(迭代实现)](#2. 非递归版归并排序(迭代实现))

核心说明

总结


归并排序是分治思想 的经典实现,核心是:拆分数组→合并有序子数组 。 时间复杂度:O(n log n) ,空间复杂度:O(n),稳定排序。

下面直接给你可直接运行 的 Java 代码,包含递归版非递归(迭代)版


1. 递归版归并排序(最常用)

思路:

  1. 把数组从中间拆分成左右两部分

  2. 递归排序左右子数组

  3. 合并两个有序子数组为一个有序数组

    public class MergeSort {

    复制代码
     // 对外暴露的排序方法
     public static void mergeSort(int[] arr) {
         if (arr == null || arr.length <= 1) {
             return;
         }
         // 临时数组,避免递归中频繁创建数组
         int[] temp = new int[arr.length];
         sort(arr, 0, arr.length - 1, temp);
     }
    
     // 递归拆分 + 排序
     private static void sort(int[] arr, int left, int right, int[] temp) {
         // 递归终止条件:子数组只有一个元素
         if (left >= right) {
             return;
         }
         int mid = left + (right - left) / 2; // 防止溢出
         sort(arr, left, mid, temp);      // 排序左半部分
         sort(arr, mid + 1, right, temp);  // 排序右半部分
         merge(arr, left, mid, right, temp); // 合并两个有序子数组
     }
    
     // 合并两个有序区间 [left, mid] 和 [mid+1, right]
     private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
         int i = left;    // 左数组起始指针
         int j = mid + 1; // 右数组起始指针
         int k = left;    // 临时数组指针
    
         // 把两个有序子数组按顺序放入 temp
         while (i <= mid && j <= right) {
             if (arr[i] <= arr[j]) {
                 temp[k++] = arr[i++];
             } else {
                 temp[k++] = arr[j++];
             }
         }
    
         // 拷贝左数组剩余元素
         while (i <= mid) {
             temp[k++] = arr[i++];
         }
    
         // 拷贝右数组剩余元素
         while (j <= right) {
             temp[k++] = arr[j++];
         }
    
         // 把 temp 中排好序的部分复制回原数组
         System.arraycopy(temp, left, arr, left, right - left + 1);
     }
    
     // 测试
     public static void main(String[] args) {
         int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
         System.out.println("排序前:");
         for (int num : arr) {
             System.out.print(num + " ");
         }
    
         mergeSort(arr);
    
         System.out.println("\n递归归并排序后:");
         for (int num : arr) {
             System.out.print(num + " ");
         }
     }

    }


2. 非递归版归并排序(迭代实现)

思路:

  1. 最小子数组长度 = 1开始,两两合并

  2. 子数组长度翻倍(1→2→4→8...)

  3. 直到合并成整个数组 无递归,避免栈溢出,适合大数据量

    public class MergeSortNonRecursive {

    复制代码
     public static void mergeSortNonRecursive(int[] arr) {
         if (arr == null || arr.length <= 1) {
             return;
         }
         int n = arr.length;
         int[] temp = new int[n];
         int mergeSize = 1; // 初始合并单元长度:1
    
         while (mergeSize < n) {
             // 每次从左到右依次合并两个长度为 mergeSize 的子数组
             for (int left = 0; left < n; left += mergeSize * 2) {
                 int mid = left + mergeSize - 1;
                 // 右边界不能越界
                 int right = Math.min(left + mergeSize * 2 - 1, n - 1);
                 
                 // 只有左半边,无需合并
                 if (mid >= right) {
                     break;
                 }
                 
                 // 合并逻辑和递归版完全一样
                 merge(arr, left, mid, right, temp);
             }
             // 子数组长度翻倍
             mergeSize *= 2;
         }
     }
    
     // 合并方法和递归版完全相同
     private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
         int i = left;
         int j = mid + 1;
         int k = left;
    
         while (i <= mid && j <= right) {
             if (arr[i] <= arr[j]) {
                 temp[k++] = arr[i++];
             } else {
                 temp[k++] = arr[j++];
             }
         }
         while (i <= mid) {
             temp[k++] = arr[i++];
         }
         while (j <= right) {
             temp[k++] = arr[j++];
         }
         System.arraycopy(temp, left, arr, left, right - left + 1);
     }
    
     // 测试
     public static void main(String[] args) {
         int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
         System.out.println("排序前:");
         for (int num : arr) {
             System.out.print(num + " ");
         }
    
         mergeSortNonRecursive(arr);
    
         System.out.println("\n非递归归并排序后:");
         for (int num : arr) {
             System.out.print(num + " ");
         }
     }

    }


核心说明

  1. merge 方法 两个版本的合并逻辑完全相同,是归并排序的核心。
  2. 递归 vs 非递归
    • 递归:代码简洁,易理解,大数据量可能栈溢出
    • 非递归:无栈溢出风险,效率更稳定
  3. 稳定性 相等元素不交换顺序,是稳定排序

总结

  1. 递归版:自上而下拆分,代码简洁,适合学习理解
  2. 非递归版:自下而上合并,无栈溢出,适合生产环境
  3. 两个版本时间复杂度都是 O (n log n),都需要 O (n) 临时空间
  4. 复制代码可直接运行,输出排序结果
相关推荐
Jerry1 天前
LeetCode 28. 找出字符串中第一个匹配项的下标
算法
Jerry1 天前
LeetCode 459. 重复的子字符串
算法
闲猫1 天前
Spring AI 对接Deepseek ChatModel 聊天对话
java·前端·spring
海石1 天前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石1 天前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
自信的未来1 天前
JSON 工具|Web Worker 工程化打包 + 语法自动修复 + 多语言代码生成实战
java·前端·json
Brookty1 天前
【JavaEE】线程安全(一).4:写块串行保安全、CAS
java·开发语言·java-ee·多线程·线程安全
Jerry1 天前
LeetCode 151. 反转字符串中的单词
算法
怕孤单的草丛1 天前
缓存管理面临的主要问题
java·数据库·缓存