AcWing 787.归并排序
1、题目(来源于AcWing):
给定你一个长度为n的整数数列。
请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
输入格式
输入共两行,第一行包含整数 n。
第二行包含 n 个整数(所有整数均在1~109范围内),表示整个数列。
输出格式
输出共一行,包含 n 个整数,表示排好序的数列。
数据范围
1≤n≤100000
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
2、基本思想:
用分治的思想。将一组数据从中间平分为两组,用递归将左右两组数据分别按从大到小的顺序排好序(用后面那个合二为一的方法),然后合二为一,即用两个指针分别指向两组数据的最小值,比较两个指针所指的数,小的就依次存入一个新的数组,若有左(右)组数据已排完,则将右(左)组剩下未排完的数直接一次存入新数组当中。
3、步骤:
①确定分界点:mid = (l+r)/2
②递归排序排分别排好左右两侧数据
③归并,即将左右两侧数据合二为一
4、C++代码如下(该代码借鉴AcWing网站模板题):
#include <iostream>
void merge_sort(int q[], int l, int r);
using namespace std;
const int N = 1e6 + 10;
int n, q[N], a[N];//定义一个新数组a[N]用于存放排好的数据
int main()
{
scanf("%d", &n);//输入需要排几个数
for (int i = 0; i<n; i++)
{
scanf("%d", &q[i]);
}
merge_sort(q, 0, n - 1);//引用归并排序函数
for (int i = 0; i<n; i++)
{
printf("%d ", q[i]);
}
return 0;
}
void merge_sort(int q[], int l, int r)
{
if(l >= r) return;
int mid = (r + l) >> 1;//选择终点分界,即(r + l)/ 2
merge_sort(q, l, mid);//递归排左侧数据
merge_sort(q, mid + 1, r);//递归排右侧数据
int i = l, j = mid + 1, k = 0;//i,j分别指左右侧数据的最小值,k为新数组a[N]的下标
while (i <= mid && j <= r)
{
if (q[i] <= q[j]) a[k++] = q[i++];
else a[k++] = q[j++];
}//该循环的作用是比较q[i]和q[j],将较小数存入新数组
while(i <= mid) a[k++] = q[i++];//若左侧数据还未排完,则这些一定是大数,直接依次放入新数组后面
while(j <= r) a[k++] = q[j++];//若右侧数据还未排完,则这些一定是大数,直接依次放入新数组后面
for (i=l, k=0; i<=r; i++, k++) q[i] = a[k];//因为主函数中用的是q[N]故要将新数组中排好的数据重新存入q[N]
}
//该代码借鉴AcWing网站模板题
注意事项:
要先用递归排好左右数据,比较时将较小数先存入新数组。