参考链接:
图解排序算法(四)之归并排序
归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略【分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"整合"在一起,即分而治之】。
根据图所示,首先将序列递归分解,直到分成的都是一个数,然后递归返回,数组中的小单元开始进行合并,在合并的时候进行排序,每个合成的序列都为有序序列。接下来,我们来看最后一次合并。
代码实现中,先将原数组数据复制进了temp数组,然后将合并形成的序列填进了原数组,Java实现:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MergeSort {
//算法类不允许产生任何实例
private MergeSort() {
}
//将arr[l...mid] 和arr[mid+1....r] 两部分进行归并
private static <T extends Comparable<T>> void merge(T[] arr, int l, int mid, int r) {
T[] temp = Arrays.copyOfRange(arr, l, r + 1);
//初始化,i指向左半部分的起始;j指向右半部分,索引位置为mid+1
int i = l, j = mid + 1;
for (int k = l; k <= r; k++) {
if (i > mid) {
//左半部分元素已经全部处理完毕
arr[k] = temp[j - l];
j++;
} else if (j > r) {
//右半部分元素已经全部处理完毕
arr[k] = temp[i - l];
i++;
} else if (temp[i - l].compareTo(temp[j - l]) <= 0) {
//左半部分所指元素<右半部分所指元素
arr[k] = temp[i - l];
i++;
} else {
arr[k] = temp[j - l];
j++;
}
}
}
//递归进行排序
private static <T extends Comparable<T>> void sort(T[] arr, int l, int r) {
if (l >= r)
return;
int mid = (r + l) / 2;
sort(arr, l, mid);
sort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
//T需要实现Comparable接口,即T需为可排序的
public static <T extends Comparable<T>> void mergeSort(T[] arr) {
int n = arr.length;
sort(arr, 0, n - 1);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 2, 5, 6, 1, 7, 9, 3, 0);
//T[] toArray(T[] a):返回数组,返回数组的运行时类型与指定数组的运行时类型相同
Integer[] nums = list.toArray(new Integer[0]);
mergeSort(nums);
for (Integer num : nums) {
System.out.print(num + " ");
}
}
}
归并排序是稳定的。
时间复杂度:
每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为log2n,总的平均时间复杂度为O(nlogn)。
空间复杂度:
O(n)。