1 合并排序采用的是 分治策略
a 分解:将原问题分解成一系列子问题
b 解决:递归的解决各个子问题,若问题足够小,则直接求解
c 合并:将子问题的结果合并成原问题的解
2 将n个元素分成 各含n/2个元素的子序列(重复执行分解动作,直到子程序元素足够小)
3 单个元素被视为 已排好序的
4 为做合并 需要引入辅助操作
5 合并算法的算法复杂度为 nlgn(低为2)
注意:实现时需要考虑起始下标为 0 或者 为 1 的情况,
两种方法均可实现(原理相同),但下标的不同直接导致分解方式的不同,
遇到问题时可在关键位置加入 '打印关键值' 来调试程序
void Merge(int array[], int start, int middle, int end) //合并操作的辅助函数 { int n1= middle-start; //计算数组大小 int n2= end-middle; int *left = new int[n1]; //动态分配内存 int *right = new int[n2]; for(int i=0; i<n1; ++i) //为已排好序的两组元素 分别赋值到 新的数组 { left[i] = array[start+i]; //从start开始 } for (int j=0; j<n2; ++j) { right[j] = array[middle+j]; //从middle开始 } int i=0, j=0; for(int key=start; key<end; ++key) { if (i<n1 && left[i] <= right[j]) //从已排好序的两个数组中分别抽取数据,进行比较 { array[key] = left[i++]; //插入到最初的数组里,更新下标 } else if ( j<n2 && right[j] <= left[i]) { array[key] = right[j++]; } else if (i==n1 && j<n2) //考虑left数组为空 但right数组依然还有数据时 { array[key] = right[j++]; } else if (j==n2 && i<n1) //考虑right数组为空 但left数组依然还有数据时 { array[key] = left[i++]; } } delete [] left; //释放内存 delete [] right; } //第一次调用该函数,start的下标为从零开始, //也可以不考虑下标从1开始,但实现方式(主要是分解条件及分解方法 注意下标)需要做相应修改 void MergeSort(int array[], int start, int end) { if(start+1 < end) //分解条件 子问题只有两个元素 例如 start=0,end=1 结束分解 { int middle = (start+end)/2; //分解方式 子问题为原问题的一半 //for (int i=0; i<10; ++i) //{ // cout << array[i] << " "; //} //cout << endl; MergeSort(array,start,middle); //分解方法 middle在此作为边界条件(其功能与end相同充当哨兵位,不能访问该下标) MergeSort(array,middle,end); //middle在此作为起始下标 Merge(array,start,middle,end); //例如 merge(8,9,10) 实际进行排序的只有 array[8] 与 array[9] //for (int i=0; i<10; ++i) //{ // cout << array[i] << " "; //} //cout << endl; } } void main() { //判断是否有内存泄露,需要加头文件#include <crtdbg.h> _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF); int Array[10] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; MergeSort(Array, 0, 10); for (int i=0; i<10; ++i) { cout << Array[i] << endl; } system("pause"); }