壹
基本概念:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。
排序过程:
将序列分成 n 个有序的子序列,将相邻的有序子序列两两合并,并使合并后的序列内部有序,再对合并后的子序列重复进行上述过程,最后得到完全有序的序列。若将两个有序表合并成一个有序表,称为二路归并。
贰
实例讲解:
有数组 R [ 10 ] = { 5 , 4 , 8 , 0 , 9 , 3,2 , 6,7 , 1 },另建立一个数组 R1 储存排序后的结果。
第一趟排序(颜色相同为一组序列):
5 , 4
8 , 0
9 , 3
2 , 6
7 , 1
排序后结果:
4 , 5 , 0 , 8 , 3 , 9 , 2 , 6 , 1 , 7
第二趟排序(颜色相同为一组序列):
4 , 5 , 0 , 8
3 , 9 , 2 , 6
1 , 7
排序后结果:
0 , 4 , 5 , 8 , 2 , 3 , 6 , 9 , 1 , 7
第三趟排序(颜色相同为一组序列):
0 , 4 , 5 , 8 , 2 , 3 , 6 , 9
1 , 7
排序后结果:
0 , 2 , 3 , 4 , 5 , 6 , 8 , 9 , 1 , 7
第三趟排序(颜色相同为一组序列):
0 , 2 , 3 , 4 , 5 , 6 , 8 , 9 , 1 , 7
排序后结果:
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9
叁叁
代码实现:
实现归并排序之前,需要调用"一次归并“和”一趟归并“。
(1).一次归并:把首尾相接的两个有序表R[low...mid]、R[mid+1...high]归并成有序表R[low...high].
(2) .一趟归并:把一些相互连接的有序表依次两两归并成一些更大的有序表。
1.
一次归并代码如下:
// 一次归并排序
void Merge(int low,int m,int high)
{
// 将两个有序的子序列 R [ low..m ] 和 R [ m+1..high ] 归并成一个有序的子序列 R
[ low..high ]
// 置初始值
int i=low,j=m+1,k=0;
int *R1;
// R1 是局部向量
R1=(int *)malloc((high-low+1)*sizeof(int));
// 申请空间失败
if(!R1)
{
puts("空间申请失败");
return;
}
// 两子序列非空时取其小者输出到 R1 [ k ] 上
while(i<=m&&j<=high)
R1[k++]=(R[i]<=R[j])?R[i++]:R[j++];
// 若子序列非空,则复制剩余记录到 R1 中
while(i<=m)
R1[k++]=R[i++];
while(j<=high)
R1[k++]=R[j++];
// 归并完成后将结果复制回 R [ low..high ]
for(k=0,i=low;i<=high;k++,i++)
R[i]=R1[k];
}
2.
一趟归并代码如下:
// 一趟归并排序
void mergepass(int n,int len)
{
int i,t;
i=1;
while(i<=n-2*len+1)
{
Merge(i,i+len-1,i+2*len-1);
i=i+2*len;
}
// 最后的序列长度小于 len
if(i+len-1<n)
Merge(i,i+len-1,n);
}
归并排序算法的实现有非递归和递归两种实现方式。
3.
非递归方式实现:
void mergesort(int n)
{
int len;
int *R1;
// R1 是局部向量
len=1;
while(len<n)
{
mergepass(n,len);
len=2*len;
// 输出每趟排序的结果
for(int i=1;i<=n;i++)
printf("%d ",R[i]);
printf("\n");
}
}
4.
递归方式实现:
void MergeSortDC(int low,int high,int n)
{
//用分治法对R[low..high]进行二路归并排序
int mid;
if(low<high)
{
// 区间长度大于1
mid=(low+high)/2;
//分解
// 递归地对R[low..mid]排序
MergeSortDC(low,mid,n);
//递归地对R[mid+1..high]排序
MergeSortDC(mid+1,high,n);
// 组合,将两个有序区归并为一个有序区
Merge(low,mid,high);
}
}
肆
复杂度:
时间复杂度为 O(nlog₂n) 。这是该算法中最好、最坏和平均的时间性能。
空间复杂度为 O(n)。
比较操作的次数介于 (nlogn) / 2 和 nlogn - n + 1。
赋值操作的次数是 (2nlogn)。
归并排序比较占用内存,但却是一种效率高且稳定的算法。