Java实现归并排序算法详解

归并排序是一种经典的排序算法,它利用分治的思想,将问题分解为更小的子问题,然后将子问题的解合并起来,从而得到原问题的解。本文将通过Java代码示例详细讲解归并排序的实现过程,帮助读者更好地理解和掌握这一算法。

归并排序的基本概念

归并排序是一种稳定的排序算法,其时间复杂度为 O(nlogn)。它通过递归地将数组分成两部分,分别对这两部分进行排序,然后将排序后的两部分合并成一个有序的数组。归并排序的基本步骤如下:

  1. 分解:将数组分成两个子数组,直到每个子数组只有一个元素。最初,每个独立的元素都被视为一个有序的子序列。
  2. 合并:将两个有序的子数组合并成一个有序的数组。

Java实现归并排序

代码实现
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    private static int[] temp;// 辅助数组

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //获取数据
        String[] strs1 = br.readLine().split(" ");
        int n = Integer.parseInt(strs1[0]);
        int[] arr = new int[n];
        String[] strs = br.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(strs[i]);
        }
        //算法计算
        long start = System.currentTimeMillis();
        solution(arr);
        System.out.println("总用时:" + (System.currentTimeMillis() - start) + "ms");//把这行注释了就可以通过acwing上的题
        //输出结果
        for (int e : arr) {
            System.out.print(e + " ");
        }
        br.close();
    }

    /**
     * 解决方案函数,调用归并排序对数组进行排序
     *
     * @param arr 待排序的数组
     */
    private static void solution(int[] arr) {
        mergeSort(arr);
    }

    /**
     * 归并排序函数,使用分治法对数组进行排序
     *
     * @param arr 待排序的数组
     */
    private static void mergeSort(int[] arr) {
        int n = arr.length;
        temp = new int[n];
        for (int size = 1; size < n; size *= 2) {
            for (int i = 0; i < n; i += 2 * size) {
                int j = Math.min(i + size, n);
                int k = Math.min(j + size, n);
                if (j == k) {
                    continue;//只有一块
                } else {
                    merge(arr, i, j, k);
                }
            }
        }
    }

    /**
     * 合并两个有序数组段
     *
     * @param arr 原始数组
     * @param s1  第一个数组段的开始索引
     * @param s2  第二个数组段的开始索引
     * @param end 第二个数组段的结束索引(不包含)
     */
    private static void merge(int[] arr, int s1, int s2, int end) {
        int len = end - s1;
        int i1 = s1, i2 = s2;
        for (int i = 0; i < len; i++) {
            if (i1 >= s2) {
                temp[i] = arr[i2++]; // 如果第二个数组段已经处理完毕,则将第一个数组段的剩余元素复制到临时数组中
            } else if (i2 >= end) {
                temp[i] = arr[i1++]; // 如果第一个数组段已经处理完毕,则将第二个数组段的剩余元素复制到临时数组中
            } else {
                temp[i] = arr[i1] <= arr[i2] ? arr[i1++] : arr[i2++]; // 将较小的元素复制到临时数组中
            }
        }
        if (len >= 0) System.arraycopy(temp, 0, arr, s1, len); // 将临时数组中的元素复制回原始数组中
    }
}

代码讲解
  • 主类和主方法

    • Main 类是程序的入口类。
    • main 方法负责从标准输入读取数据,并调用 solution 方法进行排序。
    • 使用 BufferedReader 从标准输入读取数组的长度和元素。
    • 记录算法开始的时间,调用 solution 方法对数组进行排序,输出排序后的数组和算法的总用时,最后关闭 BufferedReader 以释放资源.
  • 解决方案函数

    • solution 方法是排序的入口方法,它调用 mergeSort 方法对数组进行归并排序.
  • 归并排序函数

    • 初始化一个临时数组 temp,用于在合并过程中存储中间结果.
    • 使用 size 变量控制子数组的大小,从 1 开始,每次翻倍.
    • 外层循环遍历整个数组,内层循环处理每对子数组.
    • merge 方法用于合并两个有序的子数组.
  • 合并方法

    • merge 方法用于合并两个有序的子数组:
      • s1s2 是两个子数组的起始索引,end 是合并后数组的结束索引.
      • 使用 i1i2 分别遍历两个子数组.
      • 将较小的元素放入 temp 数组中.
      • 最后将 temp 数组中的元素复制回原数组 arr 中.

性能分析

  • 时间复杂度:归并排序的时间复杂度为 O(n log n),其中 n 是待排序数组的长度。这是因为每次合并操作的时间复杂度为 O(n),而合并的层数为 log n。
  • 空间复杂度:由于需要额外的数组来存储合并过程中的临时数据,归并排序的空间复杂度为 O(n)。
  • 稳定性:归并排序是一种稳定的排序算法,因为它在合并过程中不会改变相等元素的相对顺序.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值