介绍
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
公式
其中,
为整数,并且
。
的意义参见举例中的解释部分
解释
因为排列是按字典序排名的,因此越靠前的数字优先级越高。也就是说如果两个排列的某一位之前的数字都相同,那么如果这一位如果不相同,就按这一位排序。
举例
例如, 展开为 。因为.
解释:
排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
用途
显然,位全排列后,其康托展开唯一且最大约为,因此可以由更小的空间来储存这些排列。由公式可将逆推出唯一的一个排列。
康托展开的逆运算
既然康托展开是一个双射,那么一定可以通过康托展开值求出原排列,即可以求出n的全排列中第x大排列。
如 时:
首先用 得到 ,说明 之前有 个排列.(将此数本身减去 ) 用 去除 得到 余,说明有3个数比第 位小,所以第一位是 . 用 去除 得到 余 ,说明有3个数比第 位小,所以是 ,但是 已出现过,因此是 . 用 去除 得到 余 ,类似地,这一位是 . 用 去除 得到 余 ,这一位是 . 最后一位只能是 . 所以这个数是 .
按以上方法可以得出通用的算法。
优化
树状数组
我们在处理
时,要每次统计小于当前一位数且没有被选过的数字个数,复杂度为
.
考虑使用树状数组,建树时均赋值为
,被选中后
即可。
时间复杂度为