算法评价:
-
时间复杂度:。
-
空间复杂度:。
-
稳定性:稳定。
-
适用数据规模量:大规模。
算法复杂度与数据规模量关系图:
算法说明:
如下图所示,先将待排序数组进行拆分(拆分规则多样,下图为二分法),然后再将拆分开的各个子元素进行归并(归并方式多样,下图为两路归并),得到多个小的有序的数组集合,然后再将各个有序的小数组集合归并……最终得到有序数组集合。
算法演示图:
注:此动图中采用前序遍历的方式进行归并。
Java对归并排序的实现:
/**
* 归并排序的Java实现
*
* @author JustryDeng
* @date 2019/5/6 18:38
*/
public class Merge {
/**
* 归并排序的java实现
*
* @param originArray
* 要被排序的元素集合
* @param asc
* 升序/降序。 true-升序; false-降序
*
* @date 2019/5/6 18:40
*/
public static void sort(int[] originArray, boolean asc) {
if (originArray == null || originArray.length <= 1) {
return;
}
// 数组最左边元素的索引
int left = 0;
// 数组最右边元素的索引
int right = originArray.length - 1;
splitAndMerge(originArray, left, right, asc);
}
/**
* (两路)拆分、归并 数组
*
* @param originArray
* 数组
* @param left
* 数组的起始元素索引
* @param right
* 数组的结尾元素索引
* @param asc
* 升序/降序。 true-升序; false-降序
* @date 2019/5/8 23:06
*/
private static void splitAndMerge(int[] originArray, int left, int right, boolean asc) {
// 中间那个数的索引
int center = (left + right) / 2;
/*
* 当目标区域要只有一个元素时,不再进行拆分
*
* 已知originArray长度大于0, 这里简单数学证明: 当center = right时,originArray长度为1
* ∵ center = (left + right) / 2 且 center = right
* ∴ right = (left + right) / 2
* ∴ 2 * right = left + right
* ∴ right = left
* ∴ right = left
* ∴ originArray长度为1
*/
if (center == right) {
return;
}
// 二叉树【前序遍历】, 再次进行拆分
splitAndMerge(originArray, left, center, asc);
splitAndMerge(originArray, center + 1, right, asc);
// 合并
merge(originArray, left, center, right, asc);
}
/**
* 归并两个有序的数组
*
* @param originArray
* 数组。 注:该数组由两个紧邻的 有序数组组成
* @param left
* 要归并的第一个数组的起始元素索引
* @param center
* 要归并的第一个数组的结尾元素索引
* @param right
* 要归并的第二个数组的结尾元素索引
* 注:要合并的第二个数组的结尾元素索引为center + 1
* @param asc
* 升序/降序。 true-升序; false-降序
* @date 2019/5/8 23:06
*/
private static void merge(int[] originArray, int left, int center, int right, boolean asc) {
int[] tmpArray = new int[right - left + 1];
int i = left, j = center + 1, tmpIndex = 0;
// 循环比较, 直至其中一个数组所有元素 拷贝至 tmpArray
while (i <= center && j <= right) {
// 控制升序降序
boolean ascFlag = asc ? originArray[i] <= originArray[j] : originArray[i] >= originArray[j];
if (ascFlag) {
tmpArray[tmpIndex] = originArray[i];
i++;
tmpIndex++;
} else {
tmpArray[tmpIndex] = originArray[j];
j++;
tmpIndex++;
}
}
// 将剩余那个没拷贝完的数组中剩余的元素 拷贝至 tmpArray
while (i <= center) {
tmpArray[tmpIndex] = originArray[i];
i++;
tmpIndex++;
}
while (j <= right) {
tmpArray[tmpIndex] = originArray[j];
j++;
tmpIndex++;
}
// 将临时数组中的元素按顺序拷贝至originArray
System.arraycopy(tmpArray, 0, originArray, left, tmpArray.length);
}
}
测试一下:
控制台输出:
归并排序,学习完毕!