归并排序以及逆序对统计

归并排序以及逆序对统计

1. 归并排序

归并排序利用分治的方法,将两个有序数组进行合并,达到排目的。有序数组可以通过不停地将数组进行二分,最终得到一个数,认为此数组有序。然后将两个一个数的数组进行合并,得到一个有序的有两个数据的数组,然后返回上一层继续合并,最终得到有序数列。

第一步:解决两个有序数组合并

void mergeArray(int a[],int m, int b[], int n, int re[])    //a,b,合并到re;m,n分别为a,b数组的长度
{
	int i,j,k;		//给两个数组分别设定一个指针,把两个之中较小的放在re中,本次较小的指针后移
	i=j=k=0;
	while(i<m && j<n)									//合并相同长度的数据
	{
		if(a[i]>b[j])
			re[k++]=b[j++];
		else
			re[k++]=a[i++];
	}
	while(i<m)											//多出的部分直接复制在re中
		re[k++]=a[i++];
	while(j<n)											//多出的部分直接复制在re中
		re[k++]=b[j++];
}

第二步:归并排序

void mergeArray(int a[],int left,int mid,int right, int tmp[])   
//合并a[left...mid],a[mid+1...right]
{
    int i=left,j=mid+1,k=0;
    int m=mid,n=right;
 	while(i<=m && j<=n)
	{
		if(a[i]>a[j])
			tmp[k++]=a[j++];
		else
			tmp[k++]=a[i++];
	}
	while(i<=m)
		tmp[k++]=a[i++];
	while(j<=n)
		tmp[k++]=a[j++];
    for(i=0;i<k;i++)    
 //本层合并完两个有序数组,返回到上一层位置,作为上一层的有序数组的基础,进而进行上一组的合并操作
        a[left+i]=tmp[i];
}
void mergeMain(int a[],int left, int right, int temp[])
{
    int mid;
    if(left<right)
    {
        mid=left+(right-left)/2;
        mergeMain(a,left,mid,temp);             //左边递归二分数组
        mergeMain(a,mid+1,right,temp);          //右边递归二分数组
        mergeArray(a,left,mid,right,temp);      //合并操作
    }
}
bool mergeSort(int a[],int n)
{
    int *re;
    re=new int[n];							   //一次性分配好空间,不能每次分配,释放
    if(!re)                                    //检查空间是否分配成功
        return false;
    mergeMain(a,0,n-1,re);
    delete[] re;
    re=NULL;                                    //空指针
    return true;
}

2. 逆序对

逆序对数量查找可以通过归并排序的交换次数算出,在数组a[left...mid]和a[mid+1..right],left<= i <=mid, mid+1<= j< =right ,当满足a[i] > a[j] 时存在逆序对,假设a[j]放在a[i]之前,则a[i]到a[mid](因为a数组为有序数组)的值都大于a[j],共有mid-i+1个逆序对,因此只需要在归并排序中合并数组的时候稍加改动即可

int ans=0;														 //全局变量统计数目
void mergeArray(int a[],int left,int mid,int right, int tmp[])  
{
    int i=left,j=mid+1,k=0;
    int m=mid,n=right;
 	while(i<=m && j<=n)
	{
		if(a[i]>a[j])
        {
			tmp[k++]=a[j++];
//当a[i]>a[j]的时候,如果此时把a[j]放在a[i]前面,那么a[i]到a[mid]的值都大于a[j],因此在交换之前属于逆序对
//左边数组 9 8 7  右边数组 1 2 3
//当把 1 放在 9 前面,那么9 8 7 都是 1 的逆序对,数量 mid-1+1
			ans+=mid-i+1;
        }
		else
			tmp[k++]=a[i++];
	}
	while(i<=m)
		tmp[k++]=a[i++];
	while(j<=n)
		tmp[k++]=a[j++];
    for(i=0;i<k;i++)  
        a[left+i]=tmp[i];
}
原文地址:https://www.cnblogs.com/TianyuSu/p/6350333.html