一、性能:
时间复杂度总为O(nlgn)。
二、思想:
遵循分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
算法导论对归并排序的描述是:
分解:分解待排序的n个元素的序列成各具有n/2个元素的两个子序列。
解决:使用归并排序递归地排序两个子序列。
合并:合并两个已排序的子序列以产生已排序的答案。
即,1、不断平分序列,分解至序列长度为1。(此时不用比较,长度1的每个序列都已排好序)
2、递归"回升",将两个已排序的序列通过比较进行合并。
三、例子:
96 | 20 | 60 | 33 | 72 | 02 | 42 | 57 | 22 | 50 |
对以上序列进行归并排序:
1、递归分解至序列个数为1。
-> {96,20,60,33,72,02,42,57,22,50} n = 10
-> {96,20,60,33,72},{02,42,57,22,50} n = 5
-> {96,20},{60,33,72},{02,42},{57,22,50} n = 2|3
-> {96},{20},{60},{33,72},{02},{42},{57},{22,50} n = 1|2
-> {96},{20},{60},{33},{72},{02},{42},{57},{22},{50} n =1
2、两两序列合并,递归"回升",比较排序
-> {96},{20},{60},{33},{72},{02},{42},{57},{22},{50} n = 1
-> {96},{20},{60},{33,72},{02},{42},{57},{22,50} n = 1|2
-> {20,96},{33,60,72},{02,42},{22,50,57} n = 2|3
-> {20,33,60,72,96},{02,22,42,50,57} n = 5
-> {02,20,22,33,42,50,57,60,72,96} n = 10
三、代码:
/* @param intArr 待排序输入数组 @param p 起始位置 @param q 中间位置 @param r 结束位置 @param tArr 缓存数组用于比较缓存 */ void Merge(int* intArr,int p,int q,int r,int* tArr) { int n1 = q - p+1; int n2 = r - q; int* lArr = tArr + p; int* rArr = lArr + n1 + 1; memcpy(lArr,(intArr+p),n1*sizeof(int)); // 将左序列存至lArr memcpy(rArr,(intArr+q+1),n2*sizeof(int)); // 将右序列存至lArr lArr[n1] = 0xFFFF;//极大值 用于做哨兵位,后面比较不用判断索引超出 rArr[n2] = 0xFFFF;//极大值 int i =0,j=0; for(int k=p;k<=r;++k) { if(lArr[i]<=rArr[j]) { intArr[k] = lArr[i]; ++i; } else { intArr[k] = rArr[j]; ++j; } } } /* @param intArr 待排序输入数组 @param p 起始位置 @param r 结束位置 @param tArr 缓存数组用于比较缓存 */ void MergeSort(int* intArr,int p,int r,int* tArr) { if(p<r) { int q = (p+r)/2; // 默认向下取整 MergeSort(intArr,p,q,tArr); MergeSort(intArr,q+1,r,tArr); Merge(intArr,p,q,r,tArr); } } // 实际调用函数,一开始创建足够大的tArr数组,避免重复创建删除 void MergeSort_Real(int* intArr,int p,int r) { if(p<r) { int * tArr = new int[r-p+3]; MergeSort(intArr,p,r,tArr); delete[] tArr; tArr =NULL; } }