合并排序使用了“分治法”的策略。
“将原问题划分成n个规模较小而结构与原问题相似的子问题;递归地解决这些子问题;然后合并其结果,就得到原问题的解。”这就是分治策略。
分治策略在每一层递归上有以下三个步骤:
1)分解:将原问题分解成一系列子问题;
2)解决:递归地解各子问题;
3)合并:将子问题的解合并成原问题的解。
合并排序依照上述策略:
1)分解:将n个元素分成两个含n/2个元素的子序列;
2)解决:用合并排序法对两个子序列递归地排序;
3)合并:合并两个已排序的子序列以得到排序结果。
以下代码演示了合并排序算法:
- #include <iostream>
- #include <limits>
- using namespace std;
- /*合并A[p...q]和A[q+1...r]数组,初始条件为两个字数组均有序,合并后A[p...r]有序*/
- void merge(int A[], int p, int q, int r);
- /*合并排序,排序后,A[p...r]为非递减数组*/
- void mergeSort(int A[], int p, int r);
- int main() {
- int A[10] = {20, 31, 14, 5, 11, 7, 83, 3, 5, 67};
- for(int i = 0; i < 10; i++)
- cout << A[i] << " ";
- cout << endl;
- mergeSort(A, 0, 9);
- for(int i = 0; i < 10; i++)
- cout << A[i] << " ";
- cout << endl;
- return 0;
- }
- void merge(int A[], int p, int q, int r) {
- int n1 = q - p + 1; //字数组A[p...q]长度
- int n2 = r - q; //字数组A[q+1...r]长度
- int L[n1 + 1]; //辅助数组
- int R[n2 + 1]; //辅助数组
- /*初始化*/
- for(int i = 0; i < n1; i++)
- L[i] = A[p + i];
- for(int i = 0; i < n2; i++)
- R[i] = A[q + 1 + i];
- L[n1] = numeric_limits<int>::max(); //末端置最大值,作哨兵
- R[n2] = numeric_limits<int>::max(); //同上
- /*以下循环将L,R字数组合并到A数组*/
- int i = 0, j = 0;
- for(int k = p; k <= r; k++) {
- if(L[i] <= R[j]) {
- A[k] = L[i];
- i++;
- } else {
- A[k] = R[j];
- j++;
- }
- }
- }
- void mergeSort(int A[], int p, int r) {
- if(p >= r)
- return ; //结束条件
- /*分解*/
- int q = (p + r) / 2; //取“中间”数作为分界点
- /*解决*/
- mergeSort(A, p, q); //递归排序
- mergeSort(A, q + 1, r); //同上
- /*合并*/
- merge(A, p, q, r);
- }