归并排序的步骤
归并排序是一种分治的方法,其步骤为以下几步:
- 确定分界点mid;
- 递归左右矩阵
- 将左右矩阵归一
归并与快排的区别:顺序不同。快排是先合并后递归(也可以理解为同时),归并是先递归后合并。
合并的操作
数组1已经排序:[1,3,4,6,6,8],指针 i
数组2已排序:[2,4,5,7,8,9],指针 j
归并排序的时间复杂度
为O(nlogn),与快速排序相同。
归并排序的优势:排序稳定——两数相同,位置不变。
归并排序的模板
#include <iostream>
const int N=100000;
void merge_sort(int q[N],int l,int r){
if(l>=r) return;
int mid=(l+r)>>1;/*步骤1 确定分界点*/
int tem[N];
int i=l,j=mid+1,k=0;
merge_sort(q,l,mid),merge_sort(q,mid+1,r);/*步骤2,递归*/
while(i<=mid&&j<=r){/*步骤3,归并*/
if(q[i]<q[j]) tem[k++]=q[i++];
else tem[k++]=q[j++];
}
while(i<=mid) tem[k++]=q[i++];
while(j<=r) tem[k++]=q[j++];
for(i=l,k=0;i<=r;i++,k++) q[i]=tem[k];
}
int main(){
int n;
int i;
int q[N];
scanf("%d",&n);
for(i=0;i<n;i++) scanf("%d",&q[i]);
merge_sort(q,0,n-1);
for(i=0;i<n;i++) printf("%d ",q[i]);
}
逆序对的个数
逆序对的定义
数组中任选前后两个数,前面数>后面数的数对。
[图片待插入]
求逆序对个数的步骤
求逆序对个数的思想是正统的分治思想。我们首先还是要确定数组分界点,对于逆序对存在的情况,我们可以有以下分类:
- 两个数同时在左
- 两个数同时在右
- 两个数一左一右
[图片待插入]
当pi>pj时,后面的所有数都比pj大,对应的逆序对个数就有mid-i+1个。
#include <iostream>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int q[N];
int n;
LL merge_sort(int l,int r){
if(l>=r) return 0;
int mid=(l+r)>>1;/*确定分界点*/
LL res=merge_sort(l,mid)+merge_sort(mid+1,r);/*计算两侧的逆序对*/
int tem[N];
int k=0,j=mid+1,i=l;
while(i<=mid && j<=r){
if(q[i]>q[j]){
tem[k++]=q[j++];
res+=mid-i+1;/*计算跨跃型逆序对*/
}
else tem[k++]=q[i++];
}
/*扫尾*/
while(i<=mid) tem[k++]=q[i++];/*没有继续加res*/
while(j<=r) tem[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++) q[i]=tem[j];
return res;
}
int main(){
int i;
cin>>n;
for(i=0;i<n;i++) cin>>q[i];
cout<<merge_sort(0,n-1)<<endl;
return 0;
}
还需要补充的知识点:
- 指针的用法;
- const的用法。