各处摘抄,便于详细理解掌握。
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n
a[i] 实际意义就是: 设一串数字中第n个数为s[n], a[i]表示第n个数之后的数比s[n]小的数的个数。 看以下例子,便于理解
举例:
例如,3 5 7 4 1 2 9 6 8 展开为 98884。因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.
解释:
排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
用途: 显然,n位(0~n-1)全排列后,其康托展开唯一且最大约为n!,因此可以由更小的空间来储存这些排列。由公式可将X逆推出对应的全排列。
总之就是用来压缩空间的。。
代码:
const int PermSize = 12; long long factory[PermSize] = { 0, 1, 2, 6, 24, 120,720, 5040, 40320, 362880, 3628800,39916800 }; long long Cantor(string buf) { int i, j, counted; long long result = 0; for (i = 0; i < PermSize; ++i) { counted = 0; for(j = i + 1; j < PermSize; ++j) if(buf[i] > buf[j]) ++counted; result = result + counted *factory[PermSize - i - 1]; } return result; }
康托展开的逆运算