一.步骤
归并排序算法时间复杂度为O(nlogn),归并排序是一种稳定的排序算法
1.确定分界点
在归并排序算法中,分界点的设置不像快速排序那样“随意”,而是取数组a中间下标值作为分界点,将数组a分为左和右两个部分。即:
mid = l + r >> 1;
2.递归排序“左”和“右”
在这一步中,我们假设认为我们的排序已经写好,递归相当于把数组a无限向下分割,直到数组a的子数组长度为1。
3.归并——合二为一
在第二步过后,我们会得到从小到大的两个子数组“左”和“右”,新定义两个指针i,j分别指向“左”的第一个位置,“右”的第一个位置。如图:
建立循环,比较a[i]与a[j]的大小,若a[i]<=a[j],那么我们将a[i]放入临时数组tmp,同时i++;否则将a[j]放入临时数组tmp,同时j++,直到某一个数组超出范围。
因为“左”和“右”的长度不一定相等,所以我们还要有“扫尾”工作,将剩下的数字接入临时数组tmp,代码如下:
int k=1,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
最后将排好序的数组tmp回填回数组a中即可。
二.代码
#include <iostream>
using namespace std;
const int M=1e6+10;
int a[M],tmp[M],n;
void merge_sort(int a[],int l,int r){
if(l>=r) return;
int mid=l+r>>1; //比mid=(l+r)/2快
merge_sort(a,l,mid);
merge_sort(a,mid+1,r);
int k=1,i=l,j=mid+1;
while(i<=mid&&j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
for(int i=l,j=1;i<=r;i++,j++) a[i]=tmp[j];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
merge_sort(a,1,n);
for(int i=1;i<=n;i++) printf("%d ",a[i]);
return 0;
}