分治策略:將原問題劃分紅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)中.排序