归并和快速的不同是,快速排序是先划分后递归,而归并先递归后合并。
归并排序也大体可以分为三步;
1.确定分界点;2.就是递归分左右;3.合二为一;(这里还是用算法动画图解演示)
分界点我们一般取中间;
依此类推,之后在不停的分分成单个的
之后就是合二为一以升序合并;
最后在合并一下即可;代码如下(取自AcWing)
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]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while(i<=mid) tmp[k++] = q[i++];
while(j<=r) tmp[k++] = q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i] = tmp[j];
}
接下来看几道例题;
https://www.acwing.com/problem/content/789/
模板题,直接背模板即可;
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+9;
int q[N],n,tmp[N];
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]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
while(i<=mid) tmp[k++] = q[i++];
while(j<=r) tmp[k++] = q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i] = tmp[j];
}
int main(){
cin >> 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]);
}
}
https://www.acwing.com/problem/content/790/
这里注意一下:第二个数组的数,加入备选组的时候都要统计一下:mid - i + 1,此时此刻第一个数组的数都会和他们构成逆序对。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+9;
int q[N],tmp[N],n;
ll res= 0;
void merge_sort(int q[],int l,int r){
if(l>=r) return ;
int mid = r+l >> 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]) tmp[k++] = q[i++];
else{
res += mid-i+1;
tmp[k++] = q[j++];
}
}
while(i<=mid) tmp[k++] = q[i++];
while(j<=r) tmp[k++] = q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i] = tmp[j];
}
int main(){
cin >> 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++){
cout << q[i] << " ";
}
*/
cout << res << endl;
}