冒泡排序的交换次数,即数组中逆序对的求解
【问题描述】
--------------------------------------------------
给定一个数组A=[4,6,3,2,1],求其中逆序对的个数。
答案为:6个,分别是<4,3>,<4,2>,<4.1>,<6,3>,<6,2>,<6,1>。
--------------------------------------------------
【分析】
此类问题其实就是冒泡排序的次数求解问题,若采用冒泡排序统计交换次数,则答案很明朗,时间复杂度为O(N^2),对于较长的数组,可以考虑采用其他办法降低时间复杂度,归并排序是一种很好的解决办法,其时间复杂度为O(lNogN)。(PS:此类问题的解决方案的优化是建立在对数据结构知识的大量储备上的,换句话说,来自基础)。
归并排序俗称“分治”算法,采用“分而治之”的方法,每次将要解决的问题均分成前后两半,进行求解。
详细代码(c++):
#include <iostream>
#include <malloc.h>
using namespace std;
int MergeArray(int arry[],int start,int mid,int end,int temp[])
{
//数组的归并操作
int i=mid;
int j=end;
int k=0;//临时数组末尾坐标
int count=0;
//设定两个指针ij分别指向两段有序数组的头元素,将小的那一个放入到临时数组中去。
while(i>=start&&j>mid){
if(arry[i]>arry[j]){
temp[k++]=arry[i--];//从临时数组的最后一个位置开始排序
count+=j-mid;
}
else
temp[k++]=arry[j--];
}
while(i>=start)//表示前半段数组中还有元素未放入临时数组
{
temp[k++]=arry[i--];
}
while(j>mid){
temp[k++]=arry[j--];
}
for(i=0;i<k;i++){
arry[end-i]=temp[i];//将临时数组中的元素写回到原数组当中去。
}
return count;
}
int InversePairsCore(int arry[],int start,int end,int temp[])
{
int inversions = 0;
if(start<end){
int mid=(start+end)/2;
inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序对数目
inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序对数目
inversions+=MergeArray(arry,start,mid,end,temp);//找两段之间的逆序对。最小的逆序段只有一个元素
}
return inversions;
}
int InversePairs(int arry[],int len)
{
int *temp=new int[len];
int count=InversePairsCore(arry,0,len-1,temp);
delete[] temp;
return count;
}
int main()
{
int count,k,*arry;
<span style="white-space:pre"> </span>while(cin>>k){
arry = (int *)malloc(k*sizeof(int));
for(int i=0;i<k;i++)
cin>>arry[i];
count=InversePairs(arry,k);
cout<<count<<endl;
free(arry);
}
return 0;
}