[算法定义]
将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(有序表),这种操作称为归并操作。若将两个有序表合并成一个有序表,称为二路归并。二路规并相对简单,所以重点讨论二路归并。
[算法分析]
归并排序时的时间复杂度为O(nlgn) 其主要思想是分治法(divide and conquer),分就是要将n个元素的序列划分为两个序列,再将两个序列划分为4个序列,直到每个序列只有一个元素,最后,再将两个有序序列归并成一个有序的序列。
例如两个序列:
要归并成一个有序的序列,按照我们常规的方法,我们每次从两个列表开头元素选取较小的一个,直到某一个列表到达底部,再将另一个剩下部分顺序取出。其实如果将每个元素最后添加一个最大值,则无需判断是否达到列表尽头。
如果初始是无序序列,首先把待排序区间(即无序表)中的每一个元素都看作为一个有序表,则n个元素构成n个有序表,接着两两归并(即第一个表同第二个表归并,第三个表和第四个表归并.......),得到[n/2]个长度为2的有序表(最后一个表的长度可能小于2,称此为一趟归并,然后再两丙有序表归并,得到[[n/2]/2])个长度为4的有序表(最后个表的长度可能小于4),如此进行下去,直到归并第[log2n]趟后第到一个长度为n的有序表为止。
归并排序算法我们用递归实现,先把待排序区间[s,t]以中点二分,接着把左边组织区间排个序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的[s,t]。
[参考代码]
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
void mergesort(int,int);
int a[101],r[101];//a是待排序数组,r是临时数组
int main()
{
int n,i;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i]; //输入n个待排序数据
mergesort(1,n);//对[1,n]区间的无序数据进行归并排序
for(i=1;i<=n;i++)
cout<<a[i]<<" ";//输出n个有序的数据
cout<<endl;
}
void mergesort(int s,int t)
{
int m,i,j,k;
if(s==t) return;//若区间只有一个数据就不用排了
m=(s+t)/2; //取区间的中点
mergesort(s,m);//以中点二分,对左边子区间进行排序
mergesort(m+1,t);//以中点二分,对右边子区间进行排序
i=s;
j=m+1;
k=s;
while(i<=m&&j<=t)//两个子序列从小到大合并,直到有一列结束
{
if (a[i]<=a[j])//选择较小的一个入新队列
{r[k]=a[i];i++;k++;
}
else
{r[k]=a[j];j++;k++;
}
}
while(i<=m)//把左边子序列剩余的元素接入进来
{
r[k]=a[i];i++;k++;
}
while(j<=t)//把右边子序列剩余的元素接入进来
{
r[k]=a[j];j++;k++;
}
for(i=s;i<=t;i++)
a[i]=r[i]; //把合并好的有序数据重新放入a数组
}