[模板] 归并排序 逆序数 分治

归并排序 

图来自维基

2016-07-15_归并排序.gif

递归调用的过程需要在脑中模拟清楚

然后是代码的细节问题 

多复习多理解

刘汝佳版

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;

int ans = 0;

int arr[MAXN] = {0};

int brr[MAXN] = {0};

void mergesort(int *arr, int fst, int lst, int *brr)
{
	if(lst - fst > 1)
	{
		int mid = fst + (lst - fst) / 2;
		int p = fst, q = mid, i = fst;
		
		mergesort(arr, fst, mid, brr);
		mergesort(arr, mid, lst, brr);
		
		while(p < mid || q < lst)
		{
			if(q >= lst || (p < mid && arr[p] <= arr[q]))
			{
				brr[i++] = arr[p++];
			}
			else
			{
				brr[i++] = arr[q++];
				ans += mid - p;
			}
		}
		for(i = fst; i < lst; i++)
				arr[i] = brr[i];
	}
}

int main()
{
	int n;
	
	cin>>n;
	
	for(int i = 0; i < n; i++)
		cin>>arr[i];
		
	mergesort(arr, 0, n, brr);
	
//	for(int i = 0; i < n; i++)
//		cout<<arr[i]<<'\n';
	
	cout<<ans<<'\n';
	
	return 0;
}

//正月点灯笼版

#include <iostream>
using namespace std;
long long ans = 0; //声明逆序数
void merge(int a[], int L, int M, int R)
{
	int leftlen = M - L;
	int rightlen = R - M + 1;
	int left[leftlen];
	int right[rightlen];
	int i , j , k;
	for(i = L; i < M; i++)
	{
		left[i - L] = a[i];
	}
	for(i = M; i <= R; i++)
	{
		right[i - M] = a[i];
	}
	i = 0; j = 0; k = L;
	while(i < leftlen && j < rightlen)
	{
		if(left[i] < right[j])
		{
			a[k++] = left[i++];
		}
		else
		{
			a[k++] = right[j++];
			ans += leftlen - i; //求逆序数
		}
	}
	while(i < leftlen)
	{
		a[k++] = left[i++];
	}
	while(j < rightlen)
	{
		a[k++] = right[j++];
	}
}
void merge_sort(int a[], int L, int R)
{
	if(L == R)
		return ;
	else
	{
		int M = (R + L) / 2;
		merge_sort(a, L, M); //递归分解左侧
		merge_sort(a, M + 1, R); //递归分解右侧
		merge(a,L,M + 1,R); //合并
	}
}
int main()
{
	ios::sync_with_stdio(false);
	int a[50010];
	int n;
	cin>>n;
	for(int i = 0; i < n; i++)
		cin>>a[i];
	merge_sort(a,0,n - 1);
	for(int i = 0; i < n; i++)
	{
		cout<<a[i]<<endl;
	}
	cout<<endl;
	cout<<ans<<endl;
	return 0;
}

 

posted @ 2018-04-24 20:32  张浦  阅读(89)  评论(0编辑  收藏  举报