冒泡排序的过程中每次交换就是消除一个逆序对,而比较次数由其外层循环确定,因为内层是肯定循环至结束的。
用了归并排序求逆序对,树状数组求一个数的最大逆序对数。内部循环的次数为n-1,n-2.....n-m 数列求和。
代码如下,大家可以测试下。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define lowbit(x) (-x)&(x)
#define N 110
#define M 100
using namespace std;
int num[N];
int use[N];
int tmp[N];
int vis[N];
int sum[N];
int antinum;
void mergesort(int l,int r)//归并排序求逆序数
{
if(l>=r) return;
int mid=(l+r)>>1;
mergesort(l,mid);
mergesort(mid+1,r);
int st=l,mt=mid+1,k=l;
while(st<=mid && mt<=r)
{
if(tmp[st]<=tmp[mt])
use[k++]=tmp[st++];
else
use[k++]=tmp[mt++],antinum+=mid-st+1;
}
while(st<=mid)
use[k++]=tmp[st++];
while(mt<=r)
use[k++]=tmp[mt++];
while(l<=r)
tmp[l]=use[l],l++;
}
void up(int n,int x)
{
while(n<=M)
{
sum[n]+=x;
n+=lowbit(n);
}
}
int getsum(int n)
{
int res=0;
while(n>0)
{
res+=sum[n];
n-=lowbit(n);
}
return res;
}
int main()
{
srand( time(NULL) );
antinum=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=M;i++)
{
int x=rand()%M+1;
if(vis[x]) {i--;continue;}
vis[x]=1;
num[i]=x,tmp[i]=x;
cout<<x<<endl;
}
int antimax=0;
for(int i=1;i<=M;i++)//树状数组求一个数的最大逆序数对
{
antimax=max(antimax,i-getsum(num[i]-1));
up(num[i],1);
}
mergesort(1,M);
int m=antimax*(2*M-1-antimax)/2;
int u=0,v=0;
for(int i=1;i<M;i++)
{
int tag=1;
for(int j=1;j<M-i+1;j++,v++)
if(num[j]>num[j+1]) u++,swap(num[j],num[j+1]),tag=0;
if(tag) break;
}//正常的冒泡,以便比较结果 冒泡写错好几次
cout<<u<< " "<<v<<endl;
cout<<antinum<<" "<< m<<endl;
return 0;
}