目录
一:概念定义
排序问题可以说是最经典的算法问题了,一般一开始学的基础算法就是排序,排序既是算法的基础,也是考研数据结构的重要知识点。但是 C/C++ 都有现成的库函数(C里是 qsort、C++是sort),所以导致很多人就没有学排序算法本身,其实排序算法的思路非常有意思,从最简单的学起,对以后学习复杂算法是非常有帮助的,比如快速排序和快速选择之间的关系,归并排序和逆序对之间的关系。
从今天开始,我们来试着掌握每个排序算法的思路,今天是归并排序,归并排序和快速排序有异曲同工之妙,等会娓娓道来。
归并排序,就是将两个有序的数组通过 “你来我往” 的方式合并成一个数组,如图:
图示 | 含义 |
■蓝色的柱形 | 代表尚未排好序的数 |
■ 红色的柱形 | 代表已经排好序的数 |
其他颜色 ■ 的柱形 | 正在递归、归并中的数 |
二:题目描述
给定你一个长度为 n 的整数数列,请你使用归并排序对这个数列按照从小到大进行排序。
并将排好序的数列按顺序输出。
三:算法详解
先给出个人多年使用的万能模板:
#include<iostream>
using namespace std;
const int N=100010;
int q[N],res[N];
void mergesort(int q[],int l,int r)
{
//中点递归赋值
if(l>=r) return ;
int mid=(l+r)/2;
mergesort(q,l,mid);
mergesort(q,mid+1,r);
int k=0,i=l,j=mid+1;//ij分别从两个有序数组头开始
while(i<=mid&&j<=r)
{
if(q[i]<=q[j]) res[k++]=q[i++];
else res[k++]=q[j++];
}
while(i<=mid) res[k++]=q[i++];
while(j<=r) res[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++) q[i]=res[j];
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&q[i]);
}
mergesort(q,0,n-1);
for(int i=0;i<n;i++)
{
printf("%d ",q[i]);
}
}
大致思路:
1)将每对单个元素归并为 2个元素 的有序数组;
2)将 2个元素 的每对有序数组归并成 4个元素 的有序数组,重复这个过程…;
3)最后一步:归并 2 个 n / 2个元素的排序数组(为了简化讨论,假设n是偶数)以获得完全排序的 n 个元素数组。
注:「 递归 」是自顶向下的,实际上程序真正运行过程是自底向上「 回溯 」的过程
边界分析:
mergesort(q,l,mid);mergesort(q,mid+1,r)的分界线能否改mergesort(q,l,mid-1);mergesort(q,mid,r)
显然可以,但是这时候需要改一改mid的值,因为mid=l+r>>1是向下取整,因此如果只有两个数字mid可能取到1,这会在递归的时候一半有用一半没用,而有用的一半和原来需要归并的范围都没变,因此会造成无限划分。解决方案:mid=l+r+1>>1(向上取整即可)
四:和快排代码的区别
快速排序是先进行排序再划分递归子区间
归并排序是先划分到最小区间,然后再回溯排序
创作不易,建议点赞+收藏+关注,以免变成付费资源或者找不到宝贝文章了。
基础集训结束后将开展拔高系列