排序有许多种方法,其中最为简单的sort排序与冒泡排序,但是在一些需要排序的题目中这两个方法就不好用了。
例如洛谷P1908需要用到归并排序,今天我们来简单讲解一下这个排序方法。
首先我们需要明白,归并排序其实和二分有些相似的地方,具体如图
需要依次将一个数组分成单个后,比较大小,再次合并成为一个新的且排好顺序的数组
那么我们要攻克的难点为
1 将数组依次分开
2 排序
3 合并
分开时要用到二分的思想,当左端点小于右端点时进行分割,直到将整个数组分成单个数字存在,随后进行排序与合并
if(left<right)
{
int mid=(left+right)>>1;
mmsort(arr,add,left,mid);
mmsort(arr,add,mid+1,right);
gb(arr,add,left,mid,right);
}
这里我将排序与合并写在了一起,先存入左端点与右端点,方便后续将数据存入新数组,随后在循环中将此时要判断数据放入新数组中,最后将还没有存完的数组一起放在新数组的尾端,最后将新数组中的数据覆盖原数组
int l=left,r=mid+1;
int pp=left;
while(l<=mid&&r<=right)
{
if(arr[l]<arr[r])
{
add[pp++]=arr[l++];
}
else
{
add[pp++]=arr[r++];
}
}
while(l<=mid)
{
add[pp++]=arr[l++];
}
while(r<=right)
{
add[pp++]=arr[r++];
}
while(left<=right)
{
arr[left]=add[left];
left++;
}
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
int arr[200000];
void gb(int arr[],int add[],int left,int mid,int right)
{
int l=left,r=mid+1;
int pp=left;
while(l<=mid&&r<=right)
{
if(arr[l]<arr[r])
{
add[pp++]=arr[l++];
}
else
{
add[pp++]=arr[r++];
}
}
while(l<=mid)
{
add[pp++]=arr[l++];
}
while(r<=right)
{
add[pp++]=arr[r++];
}
while(left<=right)
{
arr[left]=add[left];
left++;
}
}
void mmsort(int arr[],int add[],int left,int right)
{
if(left<right)
{
int mid=(left+right)>>1;
mmsort(arr,add,left,mid);
mmsort(arr,add,mid+1,right);
gb(arr,add,left,mid,right);
}
}
void msort(int arr[],int n)
{
int add[n+10];
mmsort(arr,add,0,n-1);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
msort(arr,n);
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
return 0;
}