给定你一个长度为 n 的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在 1∼10的9次方 范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
#include<stdio.h>
int tem[100010];
int arr[100010];
//归并排序函数
void merge_sort(int arr[],int l,int r)
{
//递归的中止情况
if(l>=r) return;
1.取中间值,用来划分左右两个序列
int mid=l+r>>1;
//这种写法是位运算符中的右移运算符,表示计算机中二进制右移一位,等价于(l+r)/2;,但位运算会快一点,由于+的优先级比>>高,因此这里不用加括号
2.把原来的序列通过递归分成长度为1的子序列
merge_sort(arr,l,mid),merge_sort(arr,mid+1,r);
3.合并子序列(归并排序主要难点)
int k=0,i=l,j=mid+1;
//想要合并,就得设置一个新的数组tem用来存放合并后的数组,k为tem的角标
//双指针遍历比较:设i和j为为两个子序列的第一个元素,由于两者已经排好序,因此可以开始一个一个比较,小的放入tem数组,然后指针往后移动一位,如此循环
while(i<=mid&&j<=r)
{
if(arr[i]<=arr[j]) tem[k++]=arr[i++];
else tem[k++]=arr[j++];
}
//当一边已经进行到底时,剩下的一边直接放入给定的tem数组中(记住两边都是已经排好序的,因此全部放进去仍然有序)
while(i<=mid) tem[k++]=arr[i++];
while(j<=r) tem[k++]=arr[j++];
for(i=l,j=0;i<=r;i++,j++) arr[i]=tem[j];//把tem数组已经排好序的数放回arr中,结束;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
merge_sort(arr,0,n-1);
for(int i=0;i<n;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
总结归并思路
1.有数组 arr, 左端点 l, 右端点 r
2.确定划分边界 mid
3.递归处理子问题 arr[l..mid], arr[mid+1..r]
4.合并子问题
(1)主体合并
至少有一个小数组添加到 tem 数组中
(2)收尾
可能存在的剩下的一个小数组的尾部直接添加到 tem 数组中
(3)复制回来
tmp 数组覆盖原数组