归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
(1)自上而下的递归(所有的递归都可以用迭代重写,故有第二种方法)
(2)自下而上的迭代
归并排序是建立在合并两个有序数列的基础上的,如何合并两个有序的数列?
首先申请两个数列长度和的空间Temp,比较两个数列的第一个数字,取其中较小的一个存入Temp,将对应数列第一个数字删除,继续比较,如果有数列为空,则将另一数列直接依次存入Temp。
归并过程两两比较,不存在跳跃比较,所以归并排序是一个稳定的排序,归并排序是一个占内存,但效率高稳定的排序。
1、算法步骤
(1)将待排序n个数字划分为n等份,每份长度为1个元素,则n份全部有序;
(2)然后两两归并,得到[n/2]个长度为2或者1的有序子序列;
(3)然后再两两归并.......,如此反复,直到得到长度为n的有序序列。
2、动画演示
3、复杂度分析
(1)向下递归实现
时间复杂度为:一趟归并需要将所有元素扫描一遍,耗费时间,由完全二叉树的深度可知,总共需次归并。
空间复杂度为:需要与原始数列同样数量空间存储归并结果,递归时深度为的栈空间。
(2)向上迭代实现
时间复杂度也为;避免了递归所需的深度为的栈空间,空间复杂度为O(n)。
4、C++代码实现
递归实现
#include<iostream>
using namespace std;
template<typename T>
/*A[]为待归并的两个数列,tmpA[]存放归并结果,L为第一个序列的左端,R、RightEnd为第二个序列的左端和右端*/
void Merge(T A[], T tmpA[], int L, int R, int RightEnd)
{
int LeftEnd = R-1;
int tmp = L;
int NumElements = RightEnd - L + 1;
while(L <= LeftEnd && R <= RightEnd)
{
if(A[L] <= A[R])//取较小值存入
tmpA[tmp++] = A[L++];
else
tmpA[tmp++] = A[R++];
}
while(L <= LeftEnd)//第一个有序数列剩余,直接拼接
tmpA[tmp++] = A[L++];
while(R <= RightEnd)//第二个有序数列剩余
tmpA[tmp++] = A[R++];
for(int i = 0;i < NumElements;i++,RightEnd--)//将归并的结果存入原来的空间
A[RightEnd] = tmpA[RightEnd];
}
template<typename T>
void MSort(T A[], T tmpA[],int L,int RightEnd)
{
int center;
if(L < RightEnd)//递归调用,直到区间长度为1返回。
{
center = (L+RightEnd)/2;
MSort(A,tmpA,L,center);
MSort(A,tmpA,center+1,RightEnd);
Merge(A,tmpA,L,center+1,RightEnd);
}
}
template<typename T>
void Merge_Sort(T A[],int N)
{
T* TmpA;
TmpA = (T*)malloc(N*sizeof(T));
if(TmpA != NULL)
{
MSort(A,TmpA,0,N-1);
free(TmpA);
}
else
cout<<"空间不足";
}
int main()
{
int A[] = {15,48,1,84,123,44,5,11,89,43};
int len = sizeof(A)/sizeof(A[0]);
Merge_Sort(A,len);
for(int i =0;i<len;i++)
cout<<A[i]<<" ";
return 0;
}
迭代实现
#include<iostream>
using namespace std;
template<typename T>
/*A[]为待归并的两个数列,tmpA[]存放归并结果,L为第一个序列的左端,R、RightEnd为第二个序列的左端和右端*/
void Merge(T A[], T tmpA[], int L, int R, int RightEnd)
{
int LeftEnd = R-1;
int tmp = L;
int NumElements = RightEnd - L + 1;
while(L <= LeftEnd && R <= RightEnd)
{
if(A[L] <= A[R])//取较小值存入
tmpA[tmp++] = A[L++];
else
tmpA[tmp++] = A[R++];
}
while(L <= LeftEnd)//第一个有序数列剩余,直接拼接
tmpA[tmp++] = A[L++];
while(R <= RightEnd)//第二个有序数列剩余
tmpA[tmp++] = A[R++];
}
template<typename T>
void Merge_pass(T A[], T TmpA[], int N, int length)
{
int i;
for(i = 0; i <= N-2*length; i += 2*length)
Merge(A, TmpA, i, i+length, i+2*length-1);
if(i+length < N)/*归并最后两个子列*/
Merge(A, TmpA, i, i+length, N-1);
else/*最后只剩下一个子序列*/
{
for(int j = i; j < N; j++)
TmpA[j] = A[j];
}
}
template<typename T>
void MergeSort(T A[], int N)
{
int length = 1;//初始化有序子数列长度
T* TmpA;
TmpA = (T*)malloc(N*sizeof(T));
if(TmpA != NULL)
{
while(length < N)
{
Merge_pass(A, TmpA, N, length);
length *= 2;
Merge_pass(TmpA, A, N, length);//可以保证最终结果保存在A中
length *= 2;
}
free(TmpA);
}
else
cout<<"空间不足";
}
int main()
{
int A[] = {15,48,1,84,123,44,5,11,89,43};
int len = sizeof(A)/sizeof(A[0]);
MergeSort(A,len);
for(int i =0;i<len;i++)
cout<<A[i]<<" ";
return 0;
}