代码呈现:
void merge_sort(int q[],int l,int r)
{
if(l>=r) return;
int mid = l + r >> 1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r){
if(q[i]<=q[j])
temp[k++]=q[i++];
else
temp[k++]=q[j++];
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++){
q[i]=temp[j];
}
}
思想:
依旧是分治加递归,但与快排不同的是归并排序是先分到不能再分后排序归并,而快排是先根据基准点分成小和大的部分,再从部分里面继续分,相当于边分边排序了
1.先确定中点mid,将其分成左右两部分。
2.递归排序左右两个部分。
3.归并两个部分并排序(最重要的一步)
代码分析:
1.先将递归停止的判断条件写在前面,当左右边界重合相遇时停止。
2.写出数组中点位置mid,将左右两部分递归排序,在最里层的时候相当于数组中的单个元素,不需要比较返回上层,接下来是比较两个数以此类推等等。
3.最重要的一步,归并两个部分,此时我们需要借助一个额外的数组储存归并后的有序数组,所以引入一个变量k记录temp数组中的元素个数,然后采用双指针的算法,引入i,j分别指向两部分各自的第一个元素,将指向的两个元素比较,较小的元素写入temp数组并让指针前移,直到其中一个指针走到尽头。此时可能出现有一个指针没有遍历完的情况,于是接下来检查两个指针是否遍历完,如果没有就将后面的所有数据都写入temp数组。
4.最后将temp数组中的元素复制到q数组中。
完整代码如下:
#include <iostream>
using namespace std;
const int N = 1e5+10;
int n;
int q[N],temp[N];
void merge_sort(int q[],int l,int r);
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&q[i]);
}
merge_sort(q,0,n-1);
for(int j=0;j<n;j++){
printf("%d ",q[j]);
}
return 0;
}
void merge_sort(int q[],int l,int r)
{
if(l>=r) return;
int mid = l + r >> 1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r){
if(q[i]<=q[j])
temp[k++]=q[i++];
else
temp[k++]=q[j++];
}
while(i<=mid) temp[k++]=q[i++];
while(j<=r) temp[k++]=q[j++];
for(int i=l,j=0;i<=r;i++,j++){
q[i]=temp[j];
}
}
(用scanf是因为题目读入数据多的时候会比较快)
另外推荐一个数据结构可视化网站,可以看到归并排序的推理过程,十分清晰