归并排序
Written By lpstudy, A man ofstriving for life.Please mark the deviation if you copy it.
1 排序描述
归并排序是一种重要的递归排序排序思想。它将一个大的问题划分成两个子问题,然后分别对两个小点的子问题进行求解,对求解后的结果合并后即为原大问题的解。由于这个是递归的,于是原来一个很大的问题,就被一点一点的拆分,最后拆分成最简单的情况,可以直接求解,然后将一点点的简单的情况逐个合并,最后即为所得。说着有些复杂,不过代码实现由于使用了递归,看起来就非常整洁明了了。
void MergeSort(整个A)
{
if(满足条件)//这实际是递归的进行条件,也可以反过来看是递归的结束条件
{
MergeSort(A的前一半); //子问题,A的前一半
MergeSort(A的后一半); //子问题,A的后一半
Merge(A的前一半,A的后一半);//两个子问题的解的合并
}
}
2 存储结构
此排序算法可以直接数组存储。下面举例说明排序过程,一共有8个元素。
l 首先将8个元素的问题分解两个4个元素的问题。即9 2 83 和 7 1 0 6
l 然后对于前面4个的问题,即9 2 8 3,同样继续分解为两个2个元素的问题,即分解为92 和 8 3。
l 再次对于前面的小小子问题92,继续分解为两个子问题9和2
l 再再次对于前面的小小小子问题9,它只有一个元素,故而肯定是有序就不用排序了。
l 开始合并过程,将9和2两个子问题合并,排序成2,9;8和3两个子问题合并为3,8
l 继续合并2,9和3,8,合并成2,3,9,8.另外的一半同样合并为0,1,6,7
l 继续合并两个子问题得到最终的结果0,1,2,3,6,7,8,9
l 结果如下图所示
索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
元素值 | 9 | 2 | 8 | 3 | 7 | 1 | 0 | 6 |
第1趟 | 2 | 9 | 3 | 8 | 1 | 7 | 0 | 6 |
第2趟 | 2 | 3 | 8 | 9 | 0 | 1 | 6 | 7 |
第3趟 | 0 | 1 | 2 | 3 | 6 | 7 | 8 | 9 |
3 算法代码
主要分为两个部分,一个是总体递归框架部分,一个是对两个子问题的merge问题。
3.1 总体框架部分
//注意递归的结束条件,即只有一个元素的时候,递归截止
typedef int ElemType;
void MergeSort(ElemTypeA[],int low, int high)
{
if(low <high)//high与low的差为元素个数,当low<high,是表明有多余个元素,表明可以继续递归。
{
int mid = (low+high)/2;
MergeSort(A,low, mid);
MergeSort(A,mid+1, high);
Merge(A,low, mid, high);
}
}
3.2 合并函数
//两个子问题的合并问题。
void Merge(ElemType A[], int low,int mid, int high)
{
//将两个有序表A[low-> mid]和A[mid+1 -> high] 合并。
//需要借助第三个表帮助合并,为了简单起见,我直接定义一个局部静态数组充当暂存数据
const int MAX_SIZE = 9999;
static ElemType H[MAX_SIZE];//辅助合并表
int m = mid++;
int k = 0;//合并后的H表的索引
while(low <=m && mid<= high)
{
if(A[low] <A[mid])
H[k++] =A[low++];
else
H[k++] =A[mid++];
}
while(low <=m)//左半还有未合并完成的
H[k++] =A[low++];
while(mid <=high)//右半还有未合并完成的
H[k++] =A[mid++];
for(inti = k-1; i >=0; --i,--high)
A[high] =H[i];//将合并的集合复制回去
}
3.3 时间复杂度
由算法过程可以看出,每一个子问题合并为O(n)的级别,每一个子问题为T(n/2),故而中时间为T(n) = 2*T(n/2) + O(n)。这个时间复杂度为O(nlgn),而且它是一个稳定排序。
对于T(n) = a*T(n/b) + f(n)的形式,算法导论中有证明
如果f(n) <, 则T(n) = O()
如果f(n)=, 则T(n) = O(*lgn)
如果f(n)>, 则T(n) = O() 其中当n趋近于无穷时,a*f(n/b)/ f(n) < 1
举例来说:
T(n)= 2T(n/2) + O(1) 其中b=a=2,故而属于第1种情况,T(n) = O(n)
T(n)= 2T(n/2) + O(n) 其中b=a=2,故而属于第2种情况,T(n) = O(n*lgn)
T(n)= 2T(n/2) + O(n*n) 其中b=a=2,故而属于第3种情况,T(n) = O(n*n)
4 执行代码和截图
4.1 完整执行代码
#include <iostream>
using namespacestd;
typedef int ElemType;
//两个子问题的合并问题。
void Merge(ElemType A[], int low,int mid, int high)
{
//将两个有序表A[low-> mid]和A[mid+1 -> high] 合并。
//需要借助第三个表帮助合并,为了简单起见,我直接定义一个局部静态数组充当暂存数据
const int MAX_SIZE = 9999;
static ElemType H[MAX_SIZE];//辅助合并表
int m = mid++;
int k = 0;//合并后的H表的索引
while(low <=m && mid<= high)
{
if(A[low] <A[mid])
H[k++] =A[low++];
else
H[k++] =A[mid++];
}
while(low <=m)//左半还有未合并完成的
H[k++] =A[low++];
while(mid <=high)//右半还有未合并完成的
H[k++] =A[mid++];
for(inti = k-1; i >=0; --i,--high)
A[high] =H[i];//将合并的集合复制回去
}
void MergeSort(ElemTypeA[],int low, int high)
{
if(low <high)//high与low的差为元素个数,当low<high,是表明有多余个元素,表明可以继续递归。
{
int mid = (low+high)/2;
MergeSort(A,low, mid);
MergeSort(A,mid+1, high);
Merge(A,low, mid, high);
}
}
void LP_MergeSort(ElemTypeA[],int len)
{
MergeSort(A, 0,len-1);
}
void PrintArray(ElemTypeA[],int len)
{
for(inti = 0; i < len; ++i)
{
printf("%3d",A[i]);
}
printf("\n");
}
int main()
{
ElemType A[] ={9,2,8,3,7,1,0,6};
int len = 8;
printf("beforeMergeSort, array is ");
PrintArray(A,len);
LP_MergeSort(A,len);
printf(" afterMergeSort, array is ");
PrintArray(A,len);
return 0;
};