Java 中的归并排序程序
简介
归并排序(Merge Sort)是一种高效的、基于分治思想的排序算法。在 Java 编程中,归并排序被广泛应用于需要对大量数据进行快速、稳定排序的场景。本文将详细介绍 Java 中归并排序程序的基础概念、使用方法、常见实践以及最佳实践,帮助读者深入理解并能高效运用这一算法。
目录
- 基础概念
- 使用方法
- 递归实现
- 迭代实现
- 常见实践
- 对整数数组排序
- 对自定义对象数组排序
- 最佳实践
- 优化策略
- 与其他排序算法结合
- 小结
- 参考资料
基础概念
归并排序的核心思想是“分而治之”(Divide and Conquer)。具体步骤如下: 1. 分解(Divide):将一个大的、未排序的数组分成两个或多个较小的子数组,直到每个子数组只包含一个元素(或非常小的规模)。 2. 解决(Conquer):对每个较小的子数组进行排序,通常可以使用简单的排序方法(在归并排序中,这一步往往是递归进行的)。 3. 合并(Merge):将排序好的子数组合并成一个有序的大数组。
归并排序是一种稳定的排序算法,这意味着相等的元素在排序前后的相对顺序保持不变。它的时间复杂度为 $O(n log n)$,空间复杂度为 $O(n)$,其中 $n$ 是数组的长度。
使用方法
递归实现
以下是 Java 中归并排序递归实现的代码示例:
public class MergeSortRecursive {
public static void mergeSort(int[] arr) {
if (arr == null || arr.length <= 1) {
return;
}
int mid = arr.length / 2;
int[] left = new int[mid];
int[] right = new int[arr.length - mid];
System.arraycopy(arr, 0, left, 0, mid);
System.arraycopy(arr, mid, right, 0, arr.length - mid);
mergeSort(left);
mergeSort(right);
merge(arr, left, right);
}
private static void merge(int[] arr, int[] left, int[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
System.out.println("Before sorting:");
for (int num : arr) {
System.out.print(num + " ");
}
mergeSort(arr);
System.out.println("\nAfter sorting:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
迭代实现
迭代实现归并排序相对复杂一些,但它避免了递归调用带来的栈空间开销。以下是迭代实现的代码示例:
public class MergeSortIterative {
public static void mergeSort(int[] arr) {
int n = arr.length;
for (int subArraySize = 1; subArraySize < n; subArraySize *= 2) {
for (int startIndex = 0; startIndex < n; startIndex += 2 * subArraySize) {
int midIndex = Math.min(startIndex + subArraySize - 1, n - 1);
int endIndex = Math.min(startIndex + 2 * subArraySize - 1, n - 1);
int[] left = new int[midIndex - startIndex + 1];
int[] right = new int[endIndex - midIndex];
System.arraycopy(arr, startIndex, left, 0, left.length);
System.arraycopy(arr, midIndex + 1, right, 0, right.length);
merge(arr, left, right, startIndex);
}
}
}
private static void merge(int[] arr, int[] left, int[] right, int startIndex) {
int i = 0, j = 0, k = startIndex;
while (i < left.length && j < right.length) {
if (left[i] <= right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
public static void main(String[] args) {
int[] arr = {12, 11, 13, 5, 6, 7};
System.out.println("Before sorting:");
for (int num : arr) {
System.out.print(num + " ");
}
mergeSort(arr);
System.out.println("\nAfter sorting:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
常见实践
对整数数组排序
上述代码示例已经展示了如何对整数数组进行归并排序。在实际应用中,只需要将待排序的整数数组传递给 mergeSort
方法即可。
对自定义对象数组排序
如果要对自定义对象数组进行排序,需要让自定义类实现 Comparable
接口,并实现 compareTo
方法来定义比较规则。以下是一个示例:
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person other) {
return this.age - other.age; // 按年龄升序排序
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MergeSortCustomObject {
public static void mergeSort(Comparable[] arr) {
if (arr == null || arr.length <= 1) {
return;
}
int mid = arr.length / 2;
Comparable[] left = new Comparable[mid];
Comparable[] right = new Comparable[arr.length - mid];
System.arraycopy(arr, 0, left, 0, mid);
System.arraycopy(arr, mid, right, 0, arr.length - mid);
mergeSort(left);
mergeSort(right);
merge(arr, left, right);
}
private static void merge(Comparable[] arr, Comparable[] left, Comparable[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i].compareTo(right[j]) <= 0) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
public static void main(String[] args) {
Person[] people = {
new Person("Alice", 25),
new Person("Bob", 20),
new Person("Charlie", 30)
};
System.out.println("Before sorting:");
for (Person person : people) {
System.out.println(person);
}
mergeSort(people);
System.out.println("\nAfter sorting:");
for (Person person : people) {
System.out.println(person);
}
}
}
最佳实践
优化策略
- 减少临时数组的创建:在合并步骤中,可以尝试复用已有的数组空间,减少不必要的临时数组创建,从而降低空间复杂度。
- 使用插入排序优化小数组:当子数组规模较小时,归并排序的递归开销可能会超过其优势。此时可以切换到插入排序,插入排序在小数组上表现更好。
与其他排序算法结合
在实际应用中,可以将归并排序与其他排序算法结合使用。例如,在数据规模较小或者数据基本有序的情况下,可以先使用插入排序或冒泡排序,然后再使用归并排序对整个数据集进行排序,以提高整体性能。
小结
本文详细介绍了 Java 中的归并排序程序,包括基础概念、递归和迭代实现方法、常见实践以及最佳实践。归并排序作为一种高效、稳定的排序算法,在各种数据处理场景中都有广泛应用。通过深入理解和掌握归并排序的原理和实现,读者可以在实际编程中灵活运用这一算法,提高程序的性能和效率。
参考资料
- 《算法导论》(Introduction to Algorithms)
- Oracle Java 官方文档
- 各大在线编程学习平台(如 LeetCode、GeeksforGeeks 等)上关于归并排序的教程和练习题