为什么归并排序能够求逆序对?
注意归并排序是从小到大的一个过程。是从相邻的两个数开始处理的,对于相邻的两个数,这两个数的交换会增加或者减少一个逆序对(不考虑相等的情况)。对于一个数组内的一部分数字,他们内部的交换不会改变外面的数字的相对逆序对数量。所以,我们只要求每个归并排序的时候的逆序对数量就可以了。
对于两个有序数对的逆序对,A1,A2。我们只需要在A2中每个元素中找到A1中比它大的就可以了。在排序的时候,遇到左边 i
比右边的
j
大的时候,我们就要考虑这个时候的逆序对,应该是mid到i
之间的所有元素。
我们现在考虑这种情况是不是全部的逆序对。我们注意,当i>j的时候,我们填入的是j,并不是i,所以i的光标位置是不动的。因为我们插入是按照大小的顺序,所以i中比j位置大的数字一定还没有插入,所以这种情况就包含了所有的逆序对.
#include <iostream>
using namespace std;
const int size = 100005;
const int lgsize = 20;
int temp[lgsize][size];
int cnt=0;
void mergesort(int lo,int hi,int depth){
if(lo>=hi) return ;
int mid = (lo+hi)/2;
mergesort(lo,mid,depth+1);
mergesort(mid+1,hi,depth+1);
int i = lo ;
int j = mid+1;
for(int k = lo ; k <= hi ; k++){
if(i>mid){
temp[depth][k]=temp[depth+1][j++];
}
else if (j>hi) {
temp[depth][k] = temp[depth+1][i++];
//cnt+=(mid-i++-1);
}
else if(temp[depth+1][i]>temp[depth+1][j]){
temp[depth][k]=temp[depth+1][j++];
cnt+=(mid-i+1);//只算i才行
}
else{
temp[depth][k]=temp[depth+1][i++];
}
}
}
int main(int argc, char const *argv[])
{
int N;
int K;
while(cin>>N>>K){
cnt = 0;
for(int i = 0 ; i < N ; i++){
cin>>temp[0][i];
}
for(int i = 1 ; i < lgsize;i++){
for(int j = 0 ; j < N ; j++){
temp[i][j]=temp[0][j];
}
}
mergesort(0,N-1,1);//注意是n-1
}
return 0;
}
特别注意相等的处理手法,只有i位置大于J位置才增加逆序对的数目,否则把i位置的填进去(就是相等的时候把左边的填进去).