归并排序是一种经典的排序算法,它利用分治的思想,将问题分解为更小的子问题,然后将子问题的解合并起来,从而得到原问题的解。本文将通过Java代码示例详细讲解归并排序的实现过程,帮助读者更好地理解和掌握这一算法。
归并排序的基本概念
归并排序是一种稳定的排序算法,其时间复杂度为 O(nlogn)。它通过递归地将数组分成两部分,分别对这两部分进行排序,然后将排序后的两部分合并成一个有序的数组。归并排序的基本步骤如下:
- 分解:将数组分成两个子数组,直到每个子数组只有一个元素。最初,每个独立的元素都被视为一个有序的子序列。
- 合并:将两个有序的子数组合并成一个有序的数组。
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
方法用于合并两个有序的子数组:s1
和s2
是两个子数组的起始索引,end
是合并后数组的结束索引.- 使用
i1
和i2
分别遍历两个子数组. - 将较小的元素放入
temp
数组中. - 最后将
temp
数组中的元素复制回原数组arr
中.
性能分析
- 时间复杂度:归并排序的时间复杂度为 O(n log n),其中 n 是待排序数组的长度。这是因为每次合并操作的时间复杂度为 O(n),而合并的层数为 log n。
- 空间复杂度:由于需要额外的数组来存储合并过程中的临时数据,归并排序的空间复杂度为 O(n)。
- 稳定性:归并排序是一种稳定的排序算法,因为它在合并过程中不会改变相等元素的相对顺序.