归并排序的步骤:
1.把要排序的数字串总中间分开,分别排左边和右边
2.对于左面的数字串,一样从中间分开,分成左和右......直到剩下1个数字时返回,把他和右边的数字归并。
注意:每次都是先对左面进行排序在排序右边,最后归并,而且为保证排序的稳定性,相等的值要把原来就在左边的排在左面 。
public class merge_sort {
public static void main(String[] args) {
int []arr = new int[]{8,6,9,4,3,9,2};
process(arr,0,arr.length-1);
for(int i = 0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
public static void process(int[]arr,int L,int R){
if(L == R){
return ;
}
int mid = L + ((R-L)>>1);
process(arr,L,mid);//L到mid排序完毕
process(arr,mid + 1,R);//mid+1到R排序完毕
merge(arr,L,mid,R);//L到mid和mid+1到R归并
}
public static void merge(int[]arr,int L,int M,int R) {
int[] help = new int[R - L + 1];//定义一个辅助空间
int i = 0;//专门给help用的下标(index),指示当前help的数组到达的位置
int p1 = L;//指向第一个数组的首位
int p2 = M + 1;//指向第二个数组的首位
while (p1 <= M && p2 <= R) { //有一个不符合证明那个数组全部元素排序完毕,跳出
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
//进入下列两个while循环中的一个
while (p1 <= M) {
help[i++] = arr[p1++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
for(i = 0; i < help.length; i++)
// !!此处有坑:为什么是 L+i 呢?因为该函数排序的是arr(L,R),起始点是L
arr[L + i] = help[i];
}
}
时间复杂度:
一共两个子程序:a = 2,每个子程序遍历总长度的1/2:b = 2,除了子程序merge的时间复杂度是O(n):d = 1
T[n] = 2 * T[n/2] + O(n)
满足情况②,所以:
时间复杂度为 O(n*logn)
master公式:也叫主定理。它提供了一种通过渐近符号表示递推关系式的方法。
应用Master定理可以很简便的求解递归方程。
T [n] = a*T[n/b] + O (N^d)
①当d<log(b,a)时,时间复杂度为O(n^(logb a))
②当d=log(b,a)时,时间复杂度为O((n^d)*logn)
③当d>log(b,a)时,时间复杂度为O(n^d)
空间复杂度:O(n) ->需要一个辅助数组存放中间排序数组
该排序是稳定的
代码来自左神,b站搜索:算法大神左程云。
欢迎交流批评指正。