归并排序核心思想:
将一个数组一分二,然后将两个数组分别排序,最后将两个有序数据合并,就完成了归并排序。

归并排序使用的是分治思想,分而治之,将一个大问题分解为n个小问题,小问题解决了,大问题也就解决了。
归并排序一般使用递归来实现,要写出递归代码的关键,写出递推公式,找到终止条件。
归并排序的递推公式:
merge_sort(p…r) = merge(merge_sort(p…q),merge_sort(q+1….r))
终止条件:q>= r
递推公式注释:
merge_sort(p…r)表示我们要排序的数组的下标在p…r区间,将这个大的数组的排序问题转化为了两个子数组排序的问题。即排序p到q区间和q+1到r区间,q=(p+r)/2,当这两个数组排序完成后,使用merge合并函数进行数组的合并,整个数组即可为有序。
再来说说merge合并函数
还是先画个图



代码实现
|
public class MergerSort<T> implements SortInf<T> {
@Override
public void sort(T[] data) {
if (null == data || data.length <= 1) {
return;
}
if (!(data[0] instanceof Comparable)) {
throw new IllegalArgumentException("data not implement compator interface");
}
// 1,归并排序操作
recurstion(data, 0, data.length - 1);
}
private void recurstion(T[] data, int start, int end) {
// 递归的终止条件
if (start >= end) {
return;
}
// 1,找到中间的索引位置
int midIndex = (start + end) / 2;
// 进行左半边数据递归操作
recurstion(data, start, midIndex);
// 进行右半边数据递归操作
recurstion(data, midIndex + 1, end);
// 进行mergesort的合并操作
merget(data, start, midIndex, midIndex + 1, end);
}
/**
* 进行数据的合并操作
*
* @param data 原始数据
* @param leftstart 左开始索引
* @param leftEnd 左结束索引
* @param rightStart 右边开始索引
* @param end 右边结束索引
*/
private void merget(T[] data, int leftstart, int leftEnd, int rightStart, int end) {
int dataLength = end - leftstart + 1;
// 声明一个目标的数组大小
T[] target = (T[]) Array.newInstance(data[0].getClass(), dataLength);
int tarIndex = 0;
int leftIndex = leftstart;
int rightIndex = rightStart;
while (leftIndex <= leftEnd && rightIndex <= end) {
// if i < j ? -1 == 0 > 1
if (((Comparable) data[leftIndex]).compareTo(data[rightIndex]) > 0) {
target[tarIndex++] = data[rightIndex++];
} else {
target[tarIndex++] = data[leftIndex++];
}
}
// 将剩余的值拷贝到目标数组中
if (leftIndex <= leftEnd) {
for (int i = leftIndex; i <= leftEnd; i++) {
target[tarIndex++] = data[i];
}
} else if (rightIndex <= end) {
for (int i = rightIndex; i <= end; i++) {
target[tarIndex++] = data[i];
}
}
// 将数据拷贝回原数组中
for (int i = leftstart; i <= end; i++) {
data[i] = target[i - leftstart];
}
System.out.println(Arrays.toString(data));
}
}
|
如何分析归并排序的时间复杂度
在递归的场景中,一个问题a可以分解为几个子问题b和c,将问题b和问题c求解后,再将问题b和问题c的结果合并,就可以得到问题a的求解
定义求解的问题,a的时间为t(a),求解b、c的时间时间分为别t(b)和t(c),合并t(b)和t(c)的时间为k,代入递推公式就各要得到:
t(a)=t(b)+t(c)+k
在归并排序中,每次都将数据一分为二,可以表示为n/2,merge合并函数每次都需要将n个数据合并,可以表示为n,递推关系式可以改写为为:
t(n)=2*t(n/2)+n
t(1)=C,,当求解的数组大小为1时,只需要常量级的时间,所以表示为C







可获得结果

再次计算






结果

再次计算






结果

总结规律
可得到


可得到k的取值

t(1)=C
将k代入



使用O表示法就是

归并排序的总结:
|
算法名称
|
最好情况时间复杂度
|
最好情况的原始数据
|
最坏情况时间复杂度
|
最坏情况的原始数据
|
平均情况时间复杂度
|
是否基于比较
|
空间复杂度
|
是否稳定排序算法
|
|
归并排序
|
O(nlogn)
|
与原始数据的有序度无关
|
O(nlogn)
|
与原始数据有序度无关
|
O(nlogn)
|
是
|
O(n)
非原地排序算法
|
移定的原地排序算法。
|