聊一聊归并排序与求逆序数的过程

关于归并排序

归并排序是众多logn级别排序算法中的一种,其优点是相对稳定,我们来看一下归并的思路

自底向上的归并

在这里我们仅介绍使用递归的自底向上的排序方法,如果不用递归的话自然就是用栈存了,用递归好看点,所谓自底向上即是考虑以下情形,在子任务解决了的情况下再来解决当前规模的任务,归并的子任务就是,我们在假设对于当前序列a

a[l,mid] && a[mid+1,r]均已经排好序的情况下,
我们去把这两个序列合并,让a[l,r]这整个序列都处于有序情况

所以在合并之前我们需要先完成 子任务

int mid = ( l + r ) >> 1 ; 
guibing(a,b,l,mid) ; 
guibing(a,b,mid+1,r) ; 

对于一个序列

[ 9 7 8 4 13 10 ]来说,变成了完成子任务后的情形
[ 7 8 9 || 4 10 13 ]我们接下来只要合并就可以了  

合并的情形先使用一个b接收结果,最后再把b数组赋给a,这个过程无法原地进行,所以很多时候需要付出多一个n的时间复杂度和空间复杂度

int k = l , indexl = l , indexr = r ; 
while ( k <= r){
	if ( index1 > mid ) b[k++] = a[indexr++] ; 
	else if ( index2 > r ) b[k++] = a[indexl++] ; 
	else  b[k++] = a[indexl]<a[indexr]?a[indexl++]:a[indexr++];
}
//最后让a=b

归并排序本身还是很简单的,不过神奇的是,它还可以通过极少的改动来让其变成求逆序数的过程

求逆序数

逆序数是什么?就是在第i个单位之前,有多少个数a[i]大,就记入答案,举个例子

[ 11 , 3 , 4 , 2 ]
11 前比 11 大的没有
3 前比 3 大的有11 ans += 1 
4 前 ans += 1 
2 前 ans += 3 
最后ans=5  

我们回到之前子任务的情形:前后两个子数组都已经被排序好了

[ 7 8 9 || 4 10 13 ]我们接下来只要合并就可以了

你会不会发现,只要4小于7,4一定小于8,9,我们可以直接ans+=3
那么我们就有了一个思路,只要

if (a[indexr] < a[indexl] )
ans += mid - indexl + 1 ;  
//也就是从当前l坐标到mid的所有单位我们都可以算进去

所以我们可以这样子改

int k = l , indexl = l , indexr = r ; 
while ( k <= r){
	if ( index1 > mid ) b[k++] = a[indexr++] ; 
	else if ( index2 > r ) b[k++] = a[indexl++] ; 
	else{
	if ( a[indexr]<a[indexl]) ans += mid - indexl + 1 ; 
	 b[k++] = a[indexl]<a[indexr]?a[indexl++]:a[indexr++];
	} 
}
//最后让a=b

怎么样,很简单吧,其实我们还有更复杂的方法,使用权值线段树可以在一定程度上保证可读性和时间复杂度,不过空间复杂度由于有树形结构的存在则是变为了原先的四倍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值