您的位置:首页 > 其它

利用归并排序求有限序列的逆序数

2013-12-08 23:24 274 查看

利用归并排序求有限序列的逆序数

逆序数对:在一个序列A={a1, a2, … , an}中,满足i<j, ai>aj­­的一对元素称为一个逆序数对。

那么,怎么求出一个序列的逆序数对的个数呢?

最简单的方法就是顺序扫描序列,求出每个元素的逆序数对,累加即可,时间复杂度是O(n2)。下面我介绍一种时间复杂度是O(nlgn)(注:lgn=log2n)的算法,它由归并排序修改而来。

在归并排序的合并过程中,左半部分元素的位置在原序列中的位置总是小于右半部分的元素,而且各个元素的相对位置在合并之前不会改变,因此利用合并的过程就可以计算出逆序数对的个数。具体做法如下,当左半部分的某个元素ai被合并时,那么右半部分中与ai比较的那个元素设为bj,则右半部分bj之前的那些元素肯定比ai小,因此形成j个逆序数对,因此总逆序数对累加j,当归并排序完成时,即可得出结果。

程序如下:

#include <iostream>

using namespace std;

//合并有序序列A[p,...,q]和A[q+1,...,r],求取A[p,...,r]区间内的逆序数
int update(int *A, int p, int q, int r)
{
int *merge = new int[r-p+1];
if (!merge)
return 0;
int i=p, j=q+1, k=0, c=0;
while(i<=q && j<=r)
{
if(A[i] <= A[j])
{
merge[k++] = A[i++];
c += j-q-1; //A[i]大于A[q+1,...,j-1],因此c增加j-q-1
}
else
{
merge[k++] = A[j++];
}
}

while(i<=q)//左半部分的元素没有合并完,则继续更新c
{
merge[k++] = A[i++];
c += j-q-1; //A[i]大于A[q+1,...,j-1],因此c增加j-q-1
}
while(j<=r)
merge[k++] = A[j++];

k=0;
while(p<=r)
{
A[p++] = merge[k++];
}
delete []merge;
return c;
}

//求A中p~r区间里逆序数对的个数,用参数c返回结果
int  nixushu(int *A, int p, int r)
{
int count = 0;
if(p < r)
{
int q = (p+r)/2;
count += nixushu(A, p, q);
count += nixushu(A, q+1, r);
count += update(A, p, q, r);
}
return count;
}

int nixushu(const int *A, int n)
{
int *copyA = new int
;
if (!copyA)
return 0;
for (int i=0; i<n; i++)
copyA[i] = A[i];
int count = nixushu(copyA, 0, n-1);
delete []copyA;
return count;
}
int main()
{
int A1[] = {0, 1, 2, 3, 4, 5, 6};
int A2[] = {6, 5, 4, 3, 2, 1, 0};
int A3[] = {4, 5, 2, 5, 6, 1, 7, 1};
int c1 = nixushu(A1, 7);
int c2 = nixushu(A2, 7);
int c3 = nixushu(A3, 8);
cout <<"A1的逆序数:" << c1 << endl;
cout <<"A2的逆序数:" << c2 << endl;
cout <<"A3的逆序数:" << c3 << endl;
return 0;
}


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