算法竞赛入门经典:第八章 高效算法设计 8.3归并排序应用之逆序对数

/*
逆序对数:
给出一列数a1,a2,...,an,求它的逆序对数,即有多少个有序对(i,j),使得i<j但ai>aj。n可以高达10^6

思路:
分解成前后两个序列,统计后序列中每个元素与前面中每个元素的逆序对数,是一个叉乘

书析:
采用O(n^2)枚举超时,因为n很大。
划分:将序列等分
递归求解:统计i和j均在左边或者均在右边的逆序对个数
合并:统计i在左边,但j在右边的个数

划分与递归都好办,
合并:如何求出i在左边,j在右边的逆序对数目。
技巧:分类,按照j的不同把这些“跨越两边”的逆序对进行分类,对于右边的每个j,统计左边比它大的元素个数f(j),所有f(j)之和便是答案。
合并操作是从小到大进行的,当右边的A[j]复制到T中时,左边没来得及复制到T的那些数就是左边所有比A[j]大的个数,及m-p,左边所剩元素在[p,m)中
因此只需要在
else
{
  iTempArr[i++] = iArr[m];
  iCnt += mid - l;//只需要加上这一句即可
}

输入:
8
1 9 6 3 4 7 9 0
输出:
0 1 3 4 6 7 9 9
13
(1+5+3+1+1+1+1=13)
*/

/*
关键:
1 采用O(n^2)枚举超时,因为n很大。 递归求解:统计i和j均在左边或者均在右边的逆序对个数  合并:统计i在左边,但j在右边的个数
2 技巧:分类,按照j的不同把这些“跨越两边”的逆序对进行分类,对于右边的每个j,统计左边比它大的元素个数f(j),所有f(j)之和便是答案。
3 合并操作是从小到大进行的,当右边的A[j]复制到T中时,左边没来得及复制到T的那些数就是左边所有比A[j]大的个数,及m-p,左边所剩元素在[p,m)中
因此只需要在
else
{
  iTempArr[i++] = iArr[m];
  iCnt += mid - l;//只需要加上这一句即可
}
4 if(m >= high || (l < mid && iArr[l] <= iArr[m]))//=与号不能漏
5 快速排序:
划分:数组重排后分成两部分,左边均<=右边
递归求解:把左右两部分分别排序
合并:不用合并,数组已经完全有序
*/
#include <stdio.h>
#define MAXSIZE 1024

int iCnt;
void mergeSort(int* iArr,int low,int high,int* iTempArr)
{
	if(1 < high - low)
	{
		int mid = low + (high - low) / 2 ;
		int l = low,m = mid,i = low;
		mergeSort(iArr,low,mid,iTempArr);
		mergeSort(iArr,mid,high,iTempArr);
		while(l < mid || m < high)
		{
			//if(m >= high || (l < mid && iArr[l] < iArr[m]))
			if(m >= high || (l < mid && iArr[l] <= iArr[m]))//=与号不能漏
			{
				iTempArr[i++] = iArr[l++];
			}
			else
			{
				iTempArr[i++] = iArr[m++];
				iCnt += mid - l;
			}
		}
		for(int j = low ; j < high ; j++)
		{
			iArr[j] = iTempArr[j];
		}
	}
}

void print(int* iArr,int n)
{
	for(int i = 0 ; i < n; i++)
	{
		if(i)
		{
			printf(" %d",iArr[i]);
		}
		else
		{
			printf("%d",iArr[i]);
		}
	}
	printf("\n");
}

void process()
{
	int n;
	while(EOF != scanf("%d",&n))
	{
		iCnt = 0;
		int iArr[MAXSIZE];
		int iTempArr[MAXSIZE];
		for(int i = 0; i < n ; i++)
		{
			scanf("%d",&iArr[i]);
		}
		mergeSort(iArr,0,n,iTempArr);
		print(iArr,n);
		printf("%d\n",iCnt);
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

你可能感兴趣的:(归并排序)