Gemini永久会员 归并排序(Merge Sort) 基于分治思想(Divide and Conquer)的高效排序算法

归并排序(Merge Sort)是一种基于分治思想(Divide and Conquer)的高效排序算法,其核心步骤包括分解、排序、合并。以下是Java中归并排序的实现及详细解析:


1. 归并排序原理

  1. 分解:将数组递归地分成两半,直到子数组长度为1(天然有序)。
  2. 排序:对两个有序子数组进行合并,生成更大的有序数组。
  3. 合并:通过双指针比较两个子数组的元素,按序合并到临时数组,再复制回原数组。

2. Java实现代码

java 复制代码
public class MergeSort {

    // 主方法:对外接口
    public static void sort(int[] arr) {
        if (arr == null || arr.length <= 1) {
            return;
        }
        int[] temp = new int[arr.length]; // 临时数组用于合并
        mergeSort(arr, 0, arr.length - 1, temp);
    }

    // 递归分治
    private static void mergeSort(int[] arr, int left, int right, int[] temp) {
        if (left < right) {
            int mid = left + (right - left) / 2; // 防止溢出
            mergeSort(arr, left, mid, temp);      // 左半部分排序
            mergeSort(arr, mid + 1, right, temp); // 右半部分排序
            merge(arr, left, mid, right, temp);   // 合并两个有序数组
        }
    }

    // 合并两个有序子数组
    private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        int i = left;    // 左子数组起始索引
        int j = mid + 1; // 右子数组起始索引
        int k = 0;       // 临时数组索引

        // 比较左右子数组元素,填入临时数组
        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, 0, arr, left, k);
    }

    public static void main(String[] args) {
        int[] arr = {12, 11, 13, 5, 6, 7};
        System.out.println("排序前: " + Arrays.toString(arr));
        sort(arr);
        System.out.println("排序后: " + Arrays.toString(arr));
    }
}

3. 关键点解析

  1. 递归终止条件 :当子数组长度为1时(left >= right)停止分解。
  2. 临时数组:避免每次合并时新建数组,提升性能。
  3. 稳定性 :归并排序是稳定的(arr[i] <= arr[j]中的等号保证相等元素的原始顺序)。
  4. 时间复杂度 :
    • 最优/最差/平均:均为 (O(n \log n)),因为分解和合并的层次均为 (\log n),每层合并操作耗时 (O(n))。
  5. 空间复杂度:(O(n)),需额外临时数组。

4. 优化方向

  1. 小数组优化:对小规模子数组(如长度<15)切换为插入排序。
  2. 避免重复拷贝 :通过参数传递临时数组的当前有效段,减少System.arraycopy调用。
  3. 并行化:利用多线程对左右子数组的排序过程并行处理(适用于大规模数据)。

5. 对比其他排序算法

算法 时间复杂度(平均) 空间复杂度 稳定性
归并排序 (O(n \log n)) (O(n)) 稳定
快速排序 (O(n \log n)) (O(\log n)) 不稳定
堆排序 (O(n \log n)) (O(1)) 不稳定

6. 适用场景

  • 大数据量排序:如外部排序(数据无法全部加载到内存)。
  • 链表排序:无需随机访问,合并操作更高效。
  • 需要稳定排序的场景:如按多关键字排序时,前序关键字的排序结果需保留。

通过分治和合并的巧妙设计,归并排序在保证稳定性的同时实现了高效排序,是理解算法分治思想的经典案例。

相关推荐
学长毕设8 小时前
基于SpringBoot的实验室资产管理系统
java·spring boot·后端
HideF8 小时前
Linux
linux·服务器·网络
zzu123zsw9 小时前
从臃肿的模板调用到声明式契约:深入 UniHttp 动态代理与多渠道生命周期扩展
java·spring boot·microsoft·unihttp
UIU11410 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
Ruiery10 小时前
Linux 6.6内核内存管理深度解析(十三):slab/slub 分配器
linux·运维·服务器
源码集结号10 小时前
云诊所门诊系统源码,基于SpringBoot+Vue.js架构,支持多租户设计与Docker容器化部署
java·spring boot·源码·医院信息系统·门诊系统·诊所系统
论文复现现场10 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi10 小时前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
啃瓜子的松鼠11 小时前
泛微OAe9-后端二开异步调用
java
秋天的怀念_David11 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法