上期我跟大家讲了快速排序,复杂度非常的不稳定,归并也是一个广泛运用的排序算法,为什么呢?
- 稳定,快速
- 递归调用,分治思想
- 合并两个有序数组的思想
- 时间复杂度O(nlog2n),这个时间复杂度的分析方法很重要一定要掌握
归并排序非常的稳定,时间复杂度不论是平均,还是最好,还是最坏,复杂度都是O(nlog2n),几乎是一成不变的。
如上图,列下来了我跟大家讲的排序算法的各个情况下的时间复杂度和空间复杂度以及稳定性。
接下来我正式讲解归并排序:
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。
算法描述
- 把长度为n的输入序列分成两个长度为n/2的子序列;
- 对这两个子序列分别采用归并排序;
- 将两个排序好的子序列合并成一个最终的排序序列。
动画演示:
归并排序代码:
void ef(int v[],int c,int m, int d,int tmp[])
{
int pb=0;
int p1=c,p2=m+1;
while(p1<=m&&p2<=d)
{
if(v[p1]<v[p2])
tmp[pb++]=v[p1++];
else
tmp[pb++]=v[p2++];
}
while(p1<=m)
tmp[pb++]=v[p1++];
while(p2<=d)
tmp[pb++]=v[p2++];
for(int i=0;i<d-c+1;++i)
v[c+i]=tmp[i];
}
void hbpx(int n[],int s,int e,int tmq[])
{
if(s<e)
{
int m=s+(e-s)/2;
hbpx(n,s,m,tmq);
hbpx(n,m+1,e,tmq);
ef(n,s,m,e,tmq);
}
}
在这里我希望大家可以熟练运用归并排序,再见。