【排序】归并排序

29 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

流程

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序;
  3. 将两个排序好的子序列合并成一个最终的排序序列。
  4. 合并:
    ①设定两个指针,最初位置分别为两个已经排序序列的起始位置。
    ②比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
    ③重复步骤③直到某一指针超出序列尾。
    ④ 将另一序列剩下的所有元素直接复制到合并序列尾。

演示

在这里插入图片描述

代码

#include <stdio.h>
#define N 1001
int n,a[N],x,b[N];
void paixu(int l,int r)
{
	if (l==r) return;
	int mid=(l+r)/2+1,i,j,t=0;
	paixu(l,mid-1);
	paixu(mid,r);
	for (i=l,j=mid;i<mid&&j<=r;)
		if (a[i]<a[j]) b[++t]=a[i++];
		else b[++t]=a[j++];
	if (i==mid)
		for (;j<=r;++j) b[++t]=a[j];
	else for (;i<mid;++i) b[++t]=a[i];
	for (i=l;i<=r;++i) a[i]=b[i-l+1];
}
int main()
{
	scanf("%d",&n);
	for (int j,i=1;i<=n;++i) scanf("%d",&a[i]);
	paixu(1,n);
	for (int i=1;i<=n;++i) printf("%d ",a[i]);
	return 0; 
} 

时间复杂度

首先,我们假设进行合并排序的数组大小为N且为2的幂,T(N)T(N)表示对其排序耗费的时间,那么就有:

  1. T(1)=1T(1)=1
  2. T(N)=2T(N2)+2NT(N)=2*T(\frac{N}{2})+2N(两个N分别为合并耗费时间和拷贝回原数组所耗费的时间)  

将2式左右除以N,得:
T(N)N=T(N2)N2+2\frac{T(N)}{N}=\frac{T(\frac{N}{2})}{\frac{N}{2}}+2

递推该式,得
T(N2)N2=T(N4)N4+2\frac{T(\frac{N}{2})}{\frac{N}{2}}=\frac{T(\frac{N}{4})}{\frac{N}{4}}+2
T(N4)N4=T(N8)N8+2\frac{T(\frac{N}{4})}{\frac{N}{4}}=\frac{T(\frac{N}{8})}{\frac{N}{8}}+2
……
T(2)2=T(1)1+2\frac{T(2)}{2}=\frac{T(1)}{1}+2

将上述所有式子左侧相加且右侧相加,得:

T(N)N+T(N2)N2+T(N4)N4++T(2)2=T(N2)N2+T(N4)N4++T(1)1+2×log2N\frac{T(N)}{N}+\frac{T(\frac{N}{2})}{\frac{N}{2}}+\frac{T(\frac{N}{4})}{\frac{N}{4}}+……+\frac{T(2)}{2} \\ =\frac{T(\frac{N}{2})}{\frac{N}{2}}+\frac{T(\frac{N}{4})}{\frac{N}{4}}+……+\frac{T(1)}{1}+2\times log_2N

化简,得:T(N)N=T(1)1+2×log2N\frac{T(N)}{N}=\frac{T(1)}{1}+2\times log_2N,即

T(N)=N+2Nlog2N=O(N×logN)T(N)=N+2*N*log_2N=O(N\times logN)

这个时间复杂度与快速排序的平均时间复杂度相同,比快速排序的最坏情况要好得多。

但是在实际应用中快速排序要比合并排序优先考虑,原因在于合并排序需要更多的内存空间,并且从tempArr拷贝数据回原数组也是一项花费巨大的工作。