分治策略:将原问题划分红n个规模较小而结构与原问题类似的子问题,而后递归地解决这些子问题,最后再合并其结果,就能够获得原问题的解。算法
它须要三个步骤:编程
经过分治策略和分治步骤,能够简单地默出归并算法。数组
书上的变量q、p、r太难理解,改成了left, middle(m), right。分别表明数组的左起点,中间分隔点,和右终点。编程语言
void merge(int * a, int left, int m, int right) { int n1 = m - left; int n2 = right - m; int *L = new int[n1]; int *R = new int[n2]; memcpy(L, a+left, n1 * sizeof(int)); memcpy(R, a+m, n2 * sizeof(int)); /* for (int i = 0; i < n1; i++) { L[i] = a[left+i]; } for (int j = 0; j < n2; j++) { R[j] = a[m+j]; } */ int i = 0; int j =0; for (int k = left; k < right; k++) { if ((j >= n2) //R已被取光了 || ((i< n1)&& (L[i] <= R[j]))) { a[k] = L[i++]; } else { // if (i>= n1) || ((j < n2) && L[i] > R[j]))) a[k] = R[j++]; } } delete[]L; delete[]R; } void mergeSort(int* a, int left, int right) { if (right - left < 2 ) { return; } int m = left + (right - left)/ 2;//分解 mergeSort(a, left, m);//递归地对两个子序列进行排序 mergeSort(a, m, right); merge(a, left, m, right);//合并 }
对于merge函数中的合并过程,有必要也用循环不变式来分析一下:函数
循环中不变的量是a[left...k) 中包含了L[0..n1), R[0..n2)中的k-left个最小元素,而且是排好序的。spa
边界条件:code
归并算法的时间复杂度是O(nlgn). 因合并时使用了两个临时数组,所以空间复杂度是O(n)blog
一样的,二分查找也是分治法的应用。应用分治步骤,能够很容易地默出二分查找法:
int binSearch(int* a, int target,int left, int right) { if (right < left ) { return -1; } int m = 0; while (left < right) { m = left + (right - left) / 2; if (a[m] == target) { return m; } else if (a[m] < target) { left = m+1; } else { right = m; } } return -1; }
采用循环不变式分析一下。循环中不变的量是:若是target存在,则它必定在数组范围[left,right)中.排序