求逆序数的三种数据结构比较

本文探讨了求逆序数问题中涉及的三种数据结构的性能和适用场景,重点比较它们在查询和插入操作上的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文比较 树状数组,线段树,还有一种unnamed的树状结构,在求逆序数中的运行效率。

给定数组a,如果有i, j, i < j且a[i] > a[j],我们称之为一个逆序(反序),求逆序数即找出这样的i,j对的数目。如果通过交换相邻元素来对数组排序,那么逆序数正好是最少的交换次数。长度为n的排列,其逆序数的期望是n(n-1)/4,方差是n(2n+5)(n-1)/72。逆序数的平均数可以大概视为n^2/4,标准差大概视为(1/6)n^(3/2)。

经典的求逆序数的算法可以由归并排序给出,但是在实现细节上可能会出错。而使用辅助数据结构则使得实现难度降低。

最简单的是用线段树:从左往右扫描,每扫描到一个数时,则通过线段树求出当前线段树上大于当前元素的元素的个数。然后将当前元素加到线段树中。

在这里,上述算法也可以用树状数组(binary index tree)来实现。在添加元素时,从大到小,可以理解为从最小元素到当前元素添加了一根线段。在查询时,从小到大累加,可以理解为求当前元素被多少个线段覆盖,也就是比当前元素大的元素的数量。

还有一种树状结构,对于[l, r]的一个区间,令mid=l+r>>1用tree[mid]来维护[mid, r]上的元素个数。
插入时,如果需要插入的元素正好是mid,则计数加1,算法结束。
如果在[mid+1, r]上,则计数加1,同时递归到右区间:l = mid + 1。
如果在[l, mid-1]上,则tree[mid]不变,同时递归到左区间上:r = mid - 1;

对于查询基本上和插入一样。


为了简单对运行效率,生成了[1, 10000]的随机数一千万个(这样的测试方法不一定能反应出效率,我只是偷懒,只简单设计这样的方法)。为了方便实现,求的是a[i] >= a[j]的pair数,否则,很多细节需要修改,而修改后,可能对于某些结构,多了一些判断,会影响效率。

对于线段树的实现,分别使用了递归和非递归,其中queryB是递归的,queryBext是非递归的。可以看出unnamed的树状结构和线段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值