逆序对:归并排序

题目描述:
给一个序列,我们使用冒泡排序法对它进行排序。请输出在排序过程中会进行多少次交换。
Input
多组读入,以n = 0结尾,该组数据不需要处理。
第一行给一个n(n < 5e5)
接下来n行有n个数a[1]~a[n],代表该序列。
(0 <= a[i] < 1e9 )
Output
输出交换次数。
思路:
题目很容易让我们直接用冒泡排序做,但是数据量很大,会直接TE,利用归并排序做。
原理:
在判断 ”治“ 的时候判断符合大于时:cnt += mid - pl + 1
来个简单的理解一下4,3,2,1,用归并排序,
第一层
4大3,cnt = 0-0+1;2大1,cnt = 1+2-2+1=2;
|3,4| |1,2|
第二层
3大2,cnt = 2+1-0+1 = 4;3大1,cnt = 4+1-0+1 = 6;为什么不在考虑4呢,因为3大1就相当考虑4了
代码:

#include <iostream>
#include <cstdio>
using namespace std;
 
int n, a[500005], tmpA[500005];
long long cnt;
void merge_sort(int l, int r, int *A) 
{
	if (l >= r) return ;
	int mid = l+(r-l)/2;
	merge_sort(l, mid, A);
	merge_sort(mid + 1, r, A);
	int pl = l, pr = mid + 1, tmpp = 0;
	while(pl <= mid && pr <= r) 
	{
		if (A[pl] <= A[pr]) 
			tmpA[tmpp++] = A[pl++];
		else 
			tmpA[tmpp++] = A[pr++], cnt += mid - pl + 1;
	}
	while(pl <= mid) 
		tmpA[tmpp++] = A[pl++];
	while(pr <= r) 
		tmpA[tmpp++] = A[pr++];
	for (int i = 0; i < tmpp; i++) 
		A[i + l] = tmpA[i];
} 
 
int main() 
{
	while(scanf("%d", &n)&&n)
	{
		cnt = 0;
		for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
		merge_sort(1, n, a);
		printf("%lld\n", cnt);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46687179/article/details/105973713