康托展开和逆康托展开是一个全排列到一个自然数的双射。(n)个数有(n!)种全排列,康托展开表示的是当前的排列在所有全排列中,按照字典序排位的顺序。
康托展开可以用来构建哈希表,压缩空间。
计算方法:
[cantor[x]=a[n]*(n-1)!+a[n-1]*(n-2)!+a[n-2]*(n-3)!+cdots +a[1]*0!
]
其中(a[i])表示在从第一个元素到第(i-1)个元素的所有未出现的元素中,小于元素i的元素个数。
比如对于三个元素({ 1,2,3}):
排列 | 康托展开 | 位次 |
---|---|---|
1 2 3 | (0*2!+0*1!+0*0!=0) | 1 |
1 3 2 | (0*2!+1*1!+0*0!=1) | 2 |
2 1 3 | (1*2!+0*1!+0*0!=2) | 3 |
2 3 1 | (1*2!+1*1!+0*0!=3) | 4 |
3 1 2 | (2*2!+0*1!+0*0!=4) | 5 |
3 2 1 | (2*2!+1*1!+0*0!=5) | 6 |
康托展开可以通过两重循环实现,时间复杂度(O(n^2)),也可以使用线段树等数据结构优化。
int cantor(char* a,int n){
int cnt,hash=0;
for(int i=0;i<n;i++){
cnt=0;
for(int j=i+1;j<n;j++){
if(a[j]<a[i]) cnt++;
}
hash+=cnt*fac[n-i-1];
}
return hash;
}