逆序对及归并排序的整体思路求解过程分析

 逆序数

 

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

Input

第1行:N,N为序列的长度(n <= 50000) 
第2 - N + 1行:序列中的元素(0 <= Aii <= 10^9)

Output

输出逆序数

Sample Input

4
2
4
3
1

Sample Output

4

逆序数的求法有两种,一种是树状数组,另一种就是利用分治法来求,我们这次只考虑用分治法来求逆序数。

很显然,对一个数组来说,我们选择这个这个数组的中点,假设这个数组为a,那么我们把它分隔成为了b,c两个数组

很显然,逆序对应该有以下三种情况:

1、存在于b数组的逆序对个数

2、存在于c数组的逆序对个数

3、存在于b,c组合在一起的逆序对个数

对于前两种,我们直接递归就可以得到答案,对于第三种,我们该怎么得到呢?

我们其实在整个递归的过程中是已经对b,c进行了排序的(没错,就是归并排序),也就是说在当前的状态下,b和c都是有序的

那么问题就简单了我们从b和c的第一项开始逐个进行比较,如果b[i]<=c[j],那么我们就把b放到原数组中,否则就把c[j]放到原数组中(我们是按照从小到大来排序的),在吧c[j]放到原数组的过程中,我们就开始统计逆序对的个数了:由于b和c是有序的,所以如果c[j]<=b[i],那么从b[i]以后的所有b中的元素都是大于c[j]的,因此逆序对的个数直接+=(b数组的大小-b[i]),就这样,我们得到了这次比较产生的逆序对的个数。同时也完成了归并排序,对于n个数,我们在整个过程中递归了log(n)次,每次合并的复杂度为O(n),因此整个的复杂度为O(n*log(n))。

#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;

vector<ll> a;
ll mergecount(vector<ll> &a)
{
	ll n=a.size();
	if(n<=1) return 0;
	ll cnt=0;
	
	vector<ll> b(a.begin(),a.begin()+n/2);
	vector<ll> c(a.begin()+n/2,a.end());
	
	cnt+=mergecount(b);//第一种逆序对
	cnt+=mergecount(c);//第二种逆序对
	
	ll ai=0,bi=0,ci=0;
	while(ai<n){//第三种逆序对的求解以及O(n)合并
		if(bi<b.size()&&(ci==c.size()||b[bi]<=c[ci])){
			a[ai++]=b[bi++];
		}
		else{
			cnt+=n/2-bi;
			a[ai++]=c[ci++];
		}
	}
	return cnt;
}

int main()
{
	ll n,x;
	while(cin>>n&&n){
		a.clear();
	for(ll i=0;i<n;i++){
		cin>>x;
		a.push_back(x);
	}
	cout<<mergecount(a)<<endl;//逆序对的个数
	for(int i=0;i<a.size();i++) cout<<a[i]<<" ";//排序后的数组
}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
归并排序是一种经典的排序算法,它通过将待排序的序列递归地划分成较小的子序列,然后将这些子序列进行合并,最终得到一个有序的序列。在归并排序过程中,可以通过统计逆序对量来评估序列的有序程度。 使用归并排序逆序对的基本思想是:在合并两个有序子序列的过程中,如果左子序列中的元素大于右子序列中的元素,则构成了一个逆序对。在合并过程中,统计逆序对量,并将两个子序列合并成一个有序序列。 具体步骤如下: 1. 将待排序序列不断二分,直到每个子序列只有一个元素。 2. 逐层合并相邻的子序列,并在合并过程中统计逆序对量。 3. 重复步骤2,直到所有子序列合并成一个有序序列。 以下是使用归并排序逆序对的示例代码: ```python def merge_sort(arr): if len(arr) <= 1: return arr, 0 mid = len(arr) // 2 left, count_left = merge_sort(arr[:mid]) right, count_right = merge_sort(arr[mid:]) merged, count_merge = merge(left, right) return merged, count_left + count_right + count_merge def merge(left, right): merged = [] count = 0 i, j = 0, 0 while i < len(left) and j < len(right): if left[i] <= right[j]: merged.append(left[i]) i += 1 else: merged.append(right[j]) j += 1 count += len(left) - i merged.extend(left[i:]) merged.extend(right[j:]) return merged, count ``` 使用上述代码,可以通过调用`merge_sort`函求解给定序列的逆序对量。函返回排序后的序列以及逆序对量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值