归并排序求逆序数

// nixushu.cpp : 定义控制台应用程序的入口点。
//
//求数列的逆序数,在归并排序过程中,寻找逆序数,时间复杂度为归并排序的复杂度,O(NlogN),空间复杂度也是归并的复杂度 此方法的空间复杂度是 2 * O(N),另外两种方法一是在递归函数内部用临时变量,另一个是和这种方法相似,不过是从a到b,再从b到a 
//#include <iostream>//放在这居然编译通不过,怪了!
#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#define N 6
using namespace std;

int mergeNixu(int *a,int *b,int low, int mid, int high)//把a中的数组归并到b,a中low到mid是有序的,mid+1到high也是有序的
{
	int nixu=0;
	if (low<high)
	{
		int l1=low,l2=mid+1;
		int i=low;//a的low到high对应b的low到high
		while(l1<=mid&&l2<=high)
		{
			if (a[l1]<=a[l2])
			{
				b[i++]=a[l1++];
			}
			else//此时a[l1]>a[l2],判断前面的部分有多少个大于当前的a[l2],即逆序的数量,是前面部分的总个数
			{
				b[i++]=a[l2++];
				nixu += mid-l1+1;//从第l1的位置到第mid 的位置都是,所以加1
			}
		}
		while(l1<=mid)b[i++]=a[l1++];
		while(l2<=high)b[i++]=a[l2++];
	}
	return nixu;
}

static int nixushu=0;

void mergeSortNixushu(int *a,int *b,int low,int high)//low,high 表示要归并的起始位置和终止位置,从a数组归并到b数组
{
	if (low==high)//仅有一个元素时
	{
		b[low]=a[low];
	}
	else
	{
		int mid = (low + high)>>1;
		mergeSortNixushu(a,b,low,mid);
		mergeSortNixushu(a,b,mid+1,high);//这步之后,b不一定是分段有序的(刚开始时,只有一个元素时肯定是有序的),所以下一步不能对b归并
		nixushu += mergeNixu(b,a,low,mid,high);//这一步归并后,保证a在low到high之间是有序的,但是b不一定是有序的
		for (int i=low;i<=high;i++)
		{
			b[i]=a[i];//每次归并后,令b=a,这样可保证b一直是分段有序的。当前这次调用后b是完全有序的,但对于上一层的递归来说,b只是其中一个部分,所以要保证b是有序的
		}
		//总结起来思路就是:不断地对a进行递归2路归并,每一段的结果暂存到b中,然后从b中归并排序到a中,这就要求b要分段有序,但此时b可能无序(因为我们从没为b排序过),但是a是分段有序的,
		//下一步的递归其实是从已经获得分段有序的序列中归并,所以要保证b也是有序的,即令b=a。
		/*for (int i=0;i<6;i++)
		{
			cout<<a[i]<<" ";
		}
		cout<<endl;
		for (int i=0;i<6;i++)
		{
			cout<<b[i]<<" ";
		}
		cout<<" once merge "<<endl;*/
	}
}
int mergeSortNixushu2(int *a,int *b,int low,int high)//非递归的方式,先对a归并中间结果放到b,然后对b归并中间结果放到a,初始值在a中,最终结果放到b中
{
	int step;
	int i,j,flag=1;
	int nixushu=0;
	if (low<high)
	{
		for (step=1;step<high;step*=2)
		{
			if (flag==1)
			{
				flag=0;
				i=low,j=i+step;
				while(i<=high&&j-1<=high)//一个步长也够的时候进不来循环之内,此时这小段数据有序,不用归并
				{
					if (j+step-1<=high)//有完整的两个步长
					{
						nixushu+=mergeNixu(a,b,i,j-1,j+step-1);
						i+=2*step;
						j=i+step;
					}
					else//只有一个完整的步长,即是最后的归并处理,所以要跳出循环
					{
						nixushu+=mergeNixu(a,b,i,j-1,high);
						break;
					}
				}
			}
			else
			{
				flag=1;
				i=low,j=i+step;
				while(i<=high&&j-1<=high)
				{
					if (j+step-1<=high)
					{
						nixushu+=mergeNixu(b,a,i,j-1,j+step-1);
						i+=2*step;
						j=i+step;
					}
					else
					{
						nixushu+= mergeNixu(b,a,i,j-1,high);
						break;
					}
				}
			}
		}
		if (flag==1)
		{
			for (int k=low;k<high;k++)
			{
				b[k]=a[k];
			}
		}
	}
	return nixushu;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int a[]={3,5,4,6,1,2};
	int b[N];
	for (int i=0;i<N;i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
	cout<<" unreversive nixushu is "<<mergeSortNixushu2(a,b,0,N-1)<<endl;
	//mergeSortNixushu(a,b,0,N-1);
	cout<<" nixushu is "<<nixushu<<endl;
	for (int i=0;i<N;i++)
	{
		cout<<b[i]<<" ";
	}
	cout<<" once merge "<<endl;
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值