数组中的逆序对

题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对,输入一个数组,求这个数组中的逆序对数。

思路分析:


代码分析:

#include<iostream>
using namespace std;

//********第一种方法:简单粗暴,时间复杂度为O(n2)***********/
int GetRevNum_1(int *arr,int len)
{
	if(arr==NULL || len<=0)								//判断参数是否合理
	{
		return 0;
	}
	int res = 0;													//记录逆序对数
	for(int i=0;i<len-1;++i)								//遍历整个数组
	{
		for(int j=i+1;j<len;++j)							//顺序和它之后的所有数据进行比较
		{
			if(arr[i] > arr[j])
				++res;
		}
	}
	return res;
}

//********第二种方法:经典归并法,时间复杂度为O(nLog2n)***********/
int Item(int *arr,int len,int pos)//分函数,功能是:算出每次归并记录的结果
{
	//归并嘛,所以肯定是两队,称之为左对和右队
	int res = 0;																			//记录本次归并逆序对数
	int low1 = 0;																		//左队头
	int high1 = pos - 1;																//左队尾
	int low2 = high1 + 1;															//右队头
	int high2 = high1 + pos > len-1 ? len-1 : high1 + pos;	    //右队尾,小心越界
	int *brr = new int[len];														//辅助数组,用来存储归并后的数组
	int index = high2;																//辅助数组的下标
	while(low2 < len)																//条件成立,则证明左队和右队都存在,可以归并
	{
		while(low1<=high1 && low2 <= high2)
		{
			if(arr[high1] > arr[high2])											//证明存在逆序对数
			{
				res += high2 - low2 + 1;											//high2小于high1了,那low2->high2的所有值都小于high1
				brr[index--] = arr[high1--];										//把数据存储在辅助空间合适的位置
			}else
			{
				brr[index--] = arr[high2--];
			}
		}
		while(low1<=high1)                                                      //左队没走完
		{
			brr[index--] = arr[high1--];
		}
		while(low2<=high2)													   //右队没走完
		{
			brr[index--] = arr[high2--];
		}
																							  //更新左队和右队
 		low1 = high2 +pos + 1;
		high1 = low1 + pos - 1;
		low2 = high1 + 1;
	    high2 = high1 + pos > len-1 ? len-1 : high1 + pos;
		index = high2;														         //更新辅助数组存储下标	
	}
	if(low2 >= len)															     //可能没构成两组,然后就把剩余的数据赋到辅助数组中去
	{
		for(int i=low1;i<len;++i)
		{
			brr[i] = arr[i];
		}
	}
	for(int i=0;i<len;++i)														//把辅助数组的值赋给新数组。
	{
		arr[i] = brr[i];
	}
	delete[] brr;
	return res;
}

int GetRevNum(int *arr,int len)//功能函数:求出总的逆序对数
{
	int res = 0;						//记录逆序对数
	if(arr==NULL || len<=0)//判断参数是否合理
	{
		return res;
	}
	for(int i=0;i+2<len;i+=2) //先比较出所有相邻数字之间的逆序对数,相当于第一次归并
	{
		if(arr[i] > arr[i+1])
		{
			++res;					//逆序对数的值随之增长
			int tmp = arr[i];  //并完成交换
			arr[i] = arr[i+1];
			arr[i+1] = tmp;
		}
	}
	for(int i=2;i<len;i*=2) //开始逐步归并
	{
		res += Item(arr,len,i);//调用分函数,并且把得到的值进行累计相加
	}
	return res;
}

int main()
{
	int num = 0;
	cin>>num;
	int *arr = new int[num];
	for(int i=0;i<num;++i)
	{
		cin>>arr[i];
	}
	cout<<GetRevNum_1(arr,num)<<endl;
	cout<<GetRevNum(arr,num)<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值