MergeSort归并排序
@(算法)
本节介绍MergeSort,归并排序是基于分治思想的,即divide-and-conquer
递归的将一个数组元素不断二分,等到实在不能分为止,开始对小数组排序,并将两个小数组merge成更大的已排序数组,直到原数组排好序为止。
MergeSort算法的时间复杂度为
O(NlogN)
先上MergeSort的代码,对算法的思路有个大致的了解:
public class Merge {
private static Comparable[] aux;
public static void sort(Comparable[] a) {
aux = new Comparable[a.length];
sort(a, 0, a.length - 1);
}
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, lo, mid);
sort(a, mid + 1, hi);
merge(a, lo, mid, hi);
}
public static void merge(Comparable[] a, int lo, int mid, int hi) {
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
aux[k] = a[k];
for (int k = 0; k < hi; k++) {
if (i > mid) a[k] = aux[i++];
else if (j > lo) a[k] = aux[j++];
else if (less(aux[j], aux[i])) a[k] = aux[j++];
else a[k] = aux[i++];
}
}
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0;
}
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
举个栗子,当需要对一个长度为16的数组进行归并排序时,程序的执行顺序为:
程序在执行
sort()
方法时递归地将数组二分,直到细分的小数组只有两个元素为止,此时程序跳出最内层的递归,开始执行最内层递归的
merge()
方法。
例如:
private static void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;//1
int mid = lo + (hi - lo) / 2;//2
sort(a, lo, mid);//3
sort(a, mid + 1, hi);//4
merge(a, lo, mid, hi);//5
}
第一次分到只有两个元素时是sort(a,0,1),代入sort()中,if()不执行,mid=0;代入sort(a,0,0),此时进入if()语句程序return,此时触发了递归终止条件,开始跳出递归慢慢往外层执行,语句3
sort(a,0,0)执行完,执行语句4
sort(a,1,1)也是return,执行merge(a,0,0,1),执行完后,此时sort(a,0,1)执行完了,开始执行语句4
sort(a,2,3)…….
为什么MergeSort复杂度为O(NlgN)
从树的角度来分析:
如上图所示,这里默认以数组长度N是2的整数次方,及2x
=N
。
这里插播一下树的相关知识点:from Wikipedia
- 树的深度:对于任意节点i,i的深度为从根到i的唯一路径长,根的深度为0;
- 树的高度:对于任意节点i,i 的高度为从i到一片树叶的最长路径长,叶子节点的高度为0.
当数组长度为N时,树有
n=lgN
层,从根节点往下,每层分别为
0,1,2,.....n−1
,每层用
k
表示。
由上图可以看到,第