您的位置:首页 > 其它

用归并排序处理逆序对问题

2016-01-03 00:19 453 查看
首先了解一下什么是逆序对,

对于一个包含N个非负整数的数组A[1..n],如果有i < j,且A[ i ]>A[ j ],则称(A[ i] ,A[ j] )为数组A中的一个逆序对。


例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。

然后了解一下什么是归并排序:
void Merge(int a[] , int low, int mid, int high,int b[]) {
int i = low; // i是第一段序列的下标
int j = mid + 1; // j是第二段序列的下标
int k = 0; // k是临时存放合并序列的下标
// b是临时合并序列
// 扫描第一段和第二段序列,直到有一个扫描结束
while (i <= mid && j <= high) {
// 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
if (a[i] <= a[j]) {
b[k] = a[i];
i++;
k++;
} else {
b[k] = a[j];
j++;
k++;
}
}
// 若第一段序列还没扫描完,将其全部复制到合并序列
while (i <= mid) {
b[k] = a[i];
i++;
k++;
}
// 若第二段序列还没扫描完,将其全部复制到合并序列
while (j <= high) {
b[k] = a[j];
j++;
k++;
}
// 将合并序列复制到原始序列中
for (k = 0, i = low; i <= high; i++, k++) {
a[i] = b[k];
}
}
void MergeSort(int a[],int low,int high,int b[])
{//用分治法对R[low..high]进行二路归并排序
int mid;
if(low<high){//区间长度大于1
mid=(low+high)/2; //分解
MergeSort(a,low,mid ,b); //递归地对R[low..mid]排序
MergeSort(a,mid+1,b); //递归地对R[mid+1..high]排序
Merge(a,low,mid,high); //组合,将两个有序区归并为一个有序区
}
}


接下来让我们看看求逆序对的代码:

#include<bits/stdc++.h>
using namespace std;
long long count1=0;//为了防止溢出,count用long long 定义
void merge(int a[],int low,int mid,int high,int b[])//合并
{
int i=low,j=mid+1,k=0;
while(i<=mid&&j<=high)    {
if(a[i]<=a[j]){
b[k++]=a[i++];
}
else{
b[k++]=a[j++];
count1+=mid-i+1;
}
}
while(i<=mid)    {
b[k++]=a[i++];
}
while(j<=high)    {
b[k++]=a[j++];
}
for(int m=0;m<k;m++)
{
a[low+m]=b[m];
}
}
void mergsort(int a[],int first,int last,int b[])//排序
{
int mid;
if(first<last)
{
mid=(first+last)/2;
mergsort(a,first,mid,b);
mergsort(a,mid+1,last,b);
merge(a,first,mid,last,b);
}
}
int main()
{
int n;
cin>>n;
int a
,b
;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
mergsort(a,0,n-1,b);
cout<<count1<<endl;
return 0;
}


两者的差别在于多了一个计数器count1。

如果左数组比右数组大,那么是逆序对,由于左右数组是有序的(从小到大),当左数组中M比右数组中N大,那么M左边的数也比右数组中的N大。所以count1=count1+mid-i+1.

伪原创。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: