[算法导论]练习2-4.d求排列中逆序对的数量
转载请注明:http://www.cnblogs.com/StartoverX/p/4283186.html
题目:给出一个确定在n个不同元素的任何排列中逆序对数量的算法,最坏情况需要Θ(nlgn)时间。(提示:修改归并排序。)
思路:修改从大到小排序的归并排序。
归并排序分为三步:分解、解决、合并。
分解:将排列A分解为A1、A2两个子排列。
解决:递归的从大到小排列A1和A2,在此同样递归的求解A1、A2的逆序对数量。
合并:按照递归排序的合并策略从大到小比较A1中的元素[a1,a2,a3…]和A2中的元素[b1,b2,b3…]。
1.若a1大于b1,则a1大于A2中的所有元素,逆序对的数量加上length(A2),将a1从A1中移至输出排列,a2继续与b1比较。
2.若a1小于b1,则b1大于A1中的所有元素,b1不能与A1中的元素构成逆序对,将b1从A2中移至输出排列,b2继续与a1比较。
3.直到A1或A2中没有元素,将剩余元素移至输出排列。
合并后的逆序对的数目为合并前A1和A2中逆序对的数目之和加上合并过程中加上的逆序对数。
#include<iostream>
using namespace std;
int A[100];
int temp1[100];
int temp2[100];
int merge(int low1,int high1,int low2,int high2){//合并步
int inver_num=0;//合并中新增的逆序对数目。
int A_pos=low1;
int size1=0;//首先将两个待合并数组复制到临时数组中。
while(low1<=high1){
temp1[size1++]=A[low1++];
}
int size2=0;
while(low2<=high2){
temp2[size2++]=A[low2++];
}
int i=0,j=0;
while(size1!=0&&size2!=0){//开始合并
if(temp1[i]>temp2[j]){
A[A_pos++]=temp1[i++];
inver_num+=size2;//逆序对数目增加。
size1-=1;
}
else{//没有相同元素。
A[A_pos++]=temp2[j++];
size2-=1;
}
}
while(size2!=0){//将剩余的元素复制到输出数组。
A[A_pos++]=temp2[j++];
size2-=1;
}
while(size1!=0){//和上面的while只会执行一个。
A[A_pos++]=temp1[i++];
size1-=1;
}
return inver_num;
}
int inversion(int low,int high){
if(low>=high)
return 0;
int mid=(low+high)/2;
int left_num=inversion(low,mid);
int right_num=inversion(mid+1,high);
int merge_num=merge(low,mid,mid+1,high);
return left_num+right_num+merge_num;
}
int main(){
int size;
cin>>size;//输入数组大小。
for(int i=0;i<size;i++){//输入数组。
cin>>A[i];
}
cout<<inversion(0,size-1)<<endl;
}