归并排序以O(N log N)最坏情形时间运行, 所使用的比较次数几乎是最优的
该算法是采用分治的思想实现, 将数组依次对半拆分, 排好序后再逐一合并
由于需要另外的一个数组来保存临时排好序的数据, 所以在空间上存在一些损耗
分治思想
分的过程将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案拼接在一起
图片来自: https://www.cnblogs.com/chengxiao/p/6194356.html
代码实现
public class MergeSort {
/*
提供给外部的方法
注意: 本方法可对任意的引用类型排序,
但需对该类型实现Comparable接口, 排序中的大小比较是通过Comparable#CompareTo方法实现
基本类型int等, 通过转换成包装类Integer即可使用
*/
public static <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType[] arr) {
AnyType[] tmpArr = (AnyType[]) new Comparable[arr.length];
mergeSort(arr, tmpArr, 0, arr.length - 1);
}
/*
将数组进行拆分, 形成类似完全二叉树的结构
*/
private static <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType[] arr, AnyType[] tmpArr, int left, int right) {
if (left < right) {
//每次对半找出中间点
int center = (left + right) / 2;
//分的过程
mergeSort(arr, tmpArr, left, center); //向左递归对折
mergeSort(arr, tmpArr, center + 1, right); //向右递归对折
//治的过程, 将拆分后的树形结构, 从左往右, 从下往上逐层排序
merge(arr, tmpArr, left, center + 1, right);
}
}
/*
通过一个临时数组, 将左右两段中的数据有序的填充到临时数组中, 就能轻松地实现排序的过程, 再将临时数组中的数据恢复到原数组即可
*/
private static <AnyType extends Comparable<? super AnyType>> void merge(AnyType[] arr, AnyType[] tmpArr,
int leftPos, int rightPos, int rightEnd) {
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int length = rightEnd - leftPos + 1;
//将左右两段中, 最小的数据依次填充到临时数组中
while (leftPos <= leftEnd && rightPos <= rightEnd) {
if (arr[leftPos].compareTo(arr[rightPos]) <= 0)
tmpArr[tmpPos++] = arr[leftPos++];
else
tmpArr[tmpPos++] = arr[rightPos++];
}
//若左段数组中还有数据, 将剩余部分直接填充到临时数组中
while (leftPos <= leftEnd)
tmpArr[tmpPos++] = arr[leftPos++];
//若右段数组中还有数据, 将剩余部分直接填充到临时数组中
while (rightPos <= rightEnd)
tmpArr[tmpPos++] = arr[rightPos++];
//将数据从临时数组中转存到原数组
for (int i = 0; i < length; i++, rightEnd--) {
arr[rightEnd] = tmpArr[rightEnd];
}
}
}
排序的中间过程结果(merge方法中)
以3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48序列为例
排序前: [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
tmpArr:[3, 44, null, null, null, null, null, null, null, null, null, null, null, null, null]
arr:[3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 44, 5, 38, null, null, null, null, null, null, null, null, null, null, null]
arr:[3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 5, 38, 44, null, null, null, null, null, null, null, null, null, null, null]
arr:[3, 44, 5, 38, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
length:4
tmpArr:[3, 5, 38, 44, 15, 47, null, null, null, null, null, null, null, null, null]
arr:[3, 5, 38, 44, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 5, 38, 44, 15, 47, 26, 36, null, null, null, null, null, null, null]
arr:[3, 5, 38, 44, 15, 47, 36, 26, 27, 2, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 5, 38, 44, 15, 26, 36, 47, null, null, null, null, null, null, null]
arr:[3, 5, 38, 44, 15, 47, 26, 36, 27, 2, 46, 4, 19, 50, 48]
length:4
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, null, null, null, null, null, null, null]
arr:[3, 5, 38, 44, 15, 26, 36, 47, 27, 2, 46, 4, 19, 50, 48]
length:8
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 27, null, null, null, null, null]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 27, 2, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 27, 4, 46, null, null, null]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 27, 46, 4, 19, 50, 48]
length:2
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, null, null, null]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 27, 4, 46, 19, 50, 48]
length:4
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, 19, 50, null]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, 19, 50, 48]
length:2
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, 19, 48, 50]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, 19, 50, 48]
length:3
tmpArr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 19, 27, 46, 48, 50]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 27, 46, 19, 48, 50]
length:7
tmpArr:[2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
arr:[3, 5, 15, 26, 36, 38, 44, 47, 2, 4, 19, 27, 46, 48, 50]
length:15
排序后: [2, 3, 4, 5, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]
动图效果