归并排序Merge sort
归并排序采用分治法的思想,将要排序的数分成一个个子问题,最终再将子问题合并,结构上是递归的,而且很多有用的算法结构上都是递归的,对递归的理解一定要透彻,如根据树的前序遍历和中序遍历恢复出原树,就采用了递归算法,总体思想我认为是将递归处理看成一个问题去处理,处理顺序也当成一个问题去思考。接下里通过对归并排序的分析,深入描述一下这种思考方式。
分治法的思想精髓在将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。分治在每层递归时都有三个步骤:
1.分解原问题为若干子问题。
2.解决这些子问题,递归的求解,如果子问题足够小,则直接得解。
3.合并这些子问题的解为原问题的解。
归并排序则完全遵守分治的三个步骤:
1.分解n个元素序列成各剧有n/2的元素的子序列。
2.递归解决子问题,归并排序解决的最小子问题为一个元素,可直接得解。
3.合并子问题。
当子问题为1时或待分解序列不可再分时,归并开始回升。
接下来分析归并排序的复杂度,分解问题使用的复杂度为常数,解决需要n*lgn,合并需要n。
归并排序的递归树的深度为lgn+1,如序列为16个元素,则分解到每个元素只有一个的时候,需要lgn+1次分解,也就是5次,16->8,8->4,4,4,4->2,2,2,2,2,2,2,2->16*1
下面给出归并排序的java实现。
public class Main { public static void main(String args[]){ int[] a = {8,7,6,5,4,3,2,1}; MERGE_sort(a,0,7); while(true); } public static void MERGE_sort(int[] a,int p,int r){ if(p<r){
//递归思想,归并排序的主体过程就是 先将问题分为两个子问题,然后解决,合并,将这三个步骤不断递归,编写程序时,只用考虑一次递归的过程就行,这一次的递归过程就简单的写为,排序左侧,排序右侧,合并。同时要加上条件判断和向深层递归的变化。 int q = (p+r)/2; MERGE_sort(a,p,q); MERGE_sort(a,q+1,r); MERGE(a,p,q,r); } } public static void MERGE(int[] a,int p,int q,int r){ int n1 = q-p+1; int n2 = r-q; int[] L = new int[n1+1]; int[] R = new int[n2+1]; for(int i = 0;i < n1;i++){ L[i] = a[p+i]; } L[n1] = 55; //哨兵值 可改成正无穷 for(int i = 0;i < n2;i++){ R[i] = a[q+1+i]; } R[n2] = 55; //哨兵值 int i=0,j=0; for(int k = p;k<=r;k++){ if(L[i] == 55){ for(int v = j;v<n2;v++){ a[k] = R[v]; k++; } break; } if(R[j] == 55){ for(int v = i;v<n1;v++){ a[k] = L[v]; k++; } break; } if(L[i]<=R[j]){ a[k] = L[i]; i++; } else{ a[k] = R[j]; j++; } } } }