归并排序介绍
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
归并排序思想
-
归并排序思想示意图:
说明:
可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用 迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程 -
归并排序合并个相邻有序子列原理
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤:
归并排序代码实现
/**
* 归并排序
*/
public class MergerSort {
public static void main(String[] args) {
int[] array = new int[80000];
int[] temp = new int[array.length];
for (int i = 0; i < array.length; i++) {
// 随机生成一个0到8000000的随机数
Random random = new Random();
int nextInt = random.nextInt(8000000);
array[i] = nextInt;
}
// 排序前时间,h毫秒
long beforeSortTimeMillis = System.currentTimeMillis();
disassembleAndMerger(array, 0, array.length - 1, temp);
// 排序后时间
long afterSortTimeMillis = System.currentTimeMillis();
System.out.println("排序总共花费时间为:" + (afterSortTimeMillis - beforeSortTimeMillis) + "毫秒");
}
/**
* 分解加合并的方法
* @param arr 需要分解和合并的数组
* @param left 左索引
* @param right 右索引
* @param temp 临时数组
*/
public static void disassembleAndMerger(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right)/2;
// 向左分解
disassembleAndMerger(arr, left, mid, temp);
// 向右分解
disassembleAndMerger(arr, mid + 1, right, temp);
// 开始合并
merger(arr, left, mid, right, temp);
}
}
/**
* 合并排序的方法
* @param arr 需要排序的数组
* @param left 最左边索引
* @param mid 中间索引
* @param right 最右边索引
* @param temp 临时数组
*/
public static void merger(int[] arr, int left, int mid, int right, int[] temp) {
// 左边数组初始索引
int i = left;
// 右边数组初始索引
int j = mid + 1;
// 临时数组初始索引
int t = 0;
// 比较左右2边数组每个数大小
while (i <= mid && j <= right) {
// 如果左边数小于右边数,就把左边数放到临时数组里面
if (arr[i] < arr[j]) {
temp[t] = arr[i];
i++;
t++;
} else {
//左边数大于或者等于右边数,就把右边数放到数组里面
temp[t] = arr[j];
j++;
t++;
}
}
// 判断2边数组是否有剩余数
while (i <= mid) {
temp[t] = arr[i];
t++;
i++;
}
while (j <= right) {
temp[t] = arr[j];
t++;
j++;
}
// 把临时数组的数复制到数组里面
int tempLeft = left;
t = 0;
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
tempLeft++;
t++;
}
}
}
我们看看运行结果,
排序总共花费时间为:10毫秒
8万个数据排序归并排序归并排序只用了10毫秒,我们再把数量级提升一个,排序80万个 数据,结果也只用了90毫秒,
归并排序时间复杂度和其他排序对比:
通过上图我们可以得知,归并排序的时间复杂度是O(nlogn)是稳定的,效率很高。