分治法
将问题分解为若干个规模小但类型原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来求原问题的解.
三个步骤
分解:把问题分解成若干个规模小的子问题,这些子问题是原问题的规模小的实例
解决:递归求解各个子问题,如果规模足够小,直接求解
合并:根据子问题的解,求原问题解
排序原理
分解:把待排序N个元素的序列分解成两个N/2个元素的子序列
解决:递归地排序两个子序列,但子序列长度为1.递归返回
合并:把两个已排序的子序列,合并成一个已排序的序列
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public static void mergeSort(int[] A, int p, int r){ if (p < r) { int q = (p + r)/2; mergeSort(A, p, q); mergeSort(A, q+1, r); merge(A, p, q, r); } } public static void merge(int[] A, int p, int q, int r){ int[] lp = new int[q - p + 1]; int[] lq = new int[r - q]; System.arraycopy(A, p, lp, 0, q - p + 1); System.arraycopy(A, q+1, lq, 0, r - q); int k = p, i, j; for (i = 0, j = 0; i < lp.length && j < lq.length; k++) { if (lp[i] > lq[j]) { A[k] = lq[j]; j++; } else { A[k] = lp[i]; i++; } } if (i < lp.length) { for (;i<lp.length;i++,k++) { A[k] = lp[i]; } } if (j < lq.length) { for (;j<lq.length;j++,k++) { A[k] = lq[j]; } } }
|
性能分析
merge方法合并N/2长两个序列需要N长时间.当子序列长度为1,递归返回时,merge合并N/2对长度为1的子序列,即总时间N.
然而这递归过程可以建立一个二叉树,N个元素当做叶子节点.非叶子节点即是两个子节点序列合并而成. 所以这颗树的高度是logN,每一层合并的时间是N.因此归并排序时间复杂度是:NlogN