题意是给出一个数组,用冒泡排序的方法将数组排序,求需要多少趟才能排完
此题如果直接按照冒泡排序的方法排序并计算次数会超时,因为时间复杂度是O(n2)
其实分析一下,我们只要求出给出的数组中有多少个逆序对即可,下面的一种解法采用了归并排序的方法来求逆序对数。
#include<cstdio>
#include<iostream>
using namespace std;
int a[500010];
long long sum;
void merge(int left,int mid,int right)
{
int i=left,j=mid+1,p;
int *temp=new int[right-left+1];
for(p=0; i<=mid&&j<=right;)
{
if(a[i]<=a[j])
temp[p++]=a[i++];
else
{
temp[p++]=a[j++];
sum+=(mid-i+1);
}
}
while(i<=mid)temp[p++]=a[i++];
while(j<=right)temp[p++]=a[j++];
for(i=left,p=0; i<=right; ++i)
a[i]=temp[p++];
delete temp;
}
void mergesort(int left,int right)
{
if(left==right)
a[left]=a[right];
if(left<right)
{
int mid=(left+right)/2;
mergesort(left,mid);
mergesort(mid+1,right);
merge(left,mid,right);
}
}
int main()
{
int n;
while(cin>>n&&n!=0)
{
sum=0;
for(int i=0; i<n; ++i)
cin>>a[i];
mergesort(0,n-1);
cout<<sum<<endl;
}
}
我抽取出关键的代码讲解一下
for(p=0; i<=mid&&j<=right;)
{
if(a[i]<=a[j])
temp[p++]=a[i++];
else
{
temp[p++]=a[j++];
sum+=(mid-i+1);
}
}
其中这两行
else
{
temp[p++]=a[j++];
sum+=(mid-i+1);
}
我举个例子来说明
比如,前面三个元素是4,5,6 后面三个元素是1,2,3
当给数组temp赋值的时候,
由于后面的小,用后面的值来赋值,
此时sum+=(mid-i+1)
mid-i+1的意思是,从i开始到mid位置的元素都比j元素大(因为从i到mid位置已经按从小到大顺序排好,如果i位置的元素比j位置的元素大,i位置后面元素的自然也比j位置的元素大)
依次类推,可以算出有多少个逆序对。
从而得出答案。