归并排序基本思想
归并排序是每次选取当前序列的中点,分为两部分,继续递归下去,直到左右两部分已经有序,然后合并的话,利用一个数组从小到大存下来左右两部分的值,然后从左端点到右端点依次赋值即可,存两部分的值其实是用到了双指针的思想
代码
#include<stdio.h>
const int N=1e5+50;
int a[N],temp[N];
void merge_sort(int l,int r){
if(l>=r) return ;
int mid=l+r>>1;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l,j=mid+1,cnt=0;
while(i<=mid && j<=r){
if(a[i]<=a[j]) temp[++cnt]=a[i++];
else temp[++cnt]=a[j++];
}
while(i<=mid) temp[++cnt]=a[i++];
while(j<=r) temp[++cnt]=a[j++];
for(i=l,j=0;i<=r;i++) a[i]=temp[++j];
}
int main(){
int n;
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
merge_sort(1,n);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
puts("");
}
return 0;
}
应该是很好懂的,归并排序难在了合并两部分的值那里。
左右两部分的起点肯定是它们那部分的最小值,因为已经处理好了,然后我们去比较这两部分内的最小值,依次加入temp数组,最后在当前区间[l,r]之间依次赋值,这样区间就是有序的了,然后在返回上一层继续重复
对比快排
与快排相比,快排是从当前区间随便选取一个基准,把小于基准的放左边,大于基准的放右边,处理完后继续递归。
而归并是选取当前区间中点,一直递归到只有两个数字,然后合并这个区间,递归返回上一层,继续合并。
快排是先处理在递归,归并是先递归在处理。
时间复杂度
每次所有小区间的处理加起来其实就是扫了一遍这个数组,O(n)。
然后归并是一半一半处理的,等于进行了logn次的合并,所以时间复杂度是O(nlogn)。