[算法导论]练习2-4.d求排列中逆序对的数量

时间:2023-10-13 13:29:19

转载请注明: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[];
int temp1[];
int temp2[];
int merge(int low1,int high1,int low2,int high2){//合并步
int inver_num=;//合并中新增的逆序对数目。
int A_pos=low1;
int size1=;//首先将两个待合并数组复制到临时数组中。
while(low1<=high1){
temp1[size1++]=A[low1++];
}
int size2=;
while(low2<=high2){
temp2[size2++]=A[low2++];
}
int i=,j=;
while(size1!=&&size2!=){//开始合并
if(temp1[i]>temp2[j]){
A[A_pos++]=temp1[i++];
inver_num+=size2;//逆序对数目增加。
size1-=;
}
else{//没有相同元素。
A[A_pos++]=temp2[j++];
size2-=;
}
} while(size2!=){//将剩余的元素复制到输出数组。
A[A_pos++]=temp2[j++];
size2-=;
}
while(size1!=){//和上面的while只会执行一个。
A[A_pos++]=temp1[i++];
size1-=;
}
return inver_num;
}
int inversion(int low,int high){
if(low>=high)
return ;
int mid=(low+high)/;
int left_num=inversion(low,mid);
int right_num=inversion(mid+,high);
int merge_num=merge(low,mid,mid+,high);
return left_num+right_num+merge_num;
} int main(){
int size;
cin>>size;//输入数组大小。
for(int i=;i<size;i++){//输入数组。
cin>>A[i];
}
cout<<inversion(,size-)<<endl;
}