详情说明可以参考其他文章,我这里是对康托展开 和 逆康托展开的JavaScript实现。
代码:
/*全排列散列 - (康托展开 和 逆康托展开)
康托展开式:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
* 例如
* 1,2,3 规定为0
* 1,3,2 规定为1
* 2,1,3 规定为2
* 2,3,1 规定为3
* 3,1,2 规定为4
* 3,2,1 规定为5
* */
// 求阶乘
function fac( x) {
let ans = 1;
for (let i = 2; i <= x; i++) {
ans *= i;
}
return ans;
}
//康托展开:对一个 a 的全排列,返回一个整数代表它在所有排列中的排名
function cantor(a) {
const n=a.length;
let ans=0;
for(let i = 0; i < n; i++) {
let temp = 0;
for (let j = i + 1; j < n; j++) {
if (a[j] < a[i]) temp++;
}
ans += temp * fac(n - i - 1);
}
return ans;
}
//逆康托展开
function decantor( x, oa)
{
const a=[].concat(oa).sort(function (n,m) {
return n-m;
})
const na=[]
const n=a.length;
let temp;
let used=[];
let i,j;
for(i=0;i<n;i++){
temp= (x/fac(n-i-1))>>0
for( j=0;j<n;j++){
if(!used[j]){
if(temp===0)break;
--temp;
}
}
na[i]=a[j];
used[j]=true;
x=x%fac(n-i-1);
}
return na;
}
测试:
//测试
const arr1=[5,2,3,4]
for(let i=0;i<fac(arr1.length);i++){
const arr=decantor(i,arr1);
console.log(cantor(arr))
console.log(arr)
}
//结果
"C:\Program Files\nodejs\node.exe" D:\test\Cantor.js
0
[ 2, 3, 4, 5 ]
1
[ 2, 3, 5, 4 ]
2
[ 2, 4, 3, 5 ]
3
[ 2, 4, 5, 3 ]
4
[ 2, 5, 3, 4 ]
5
[ 2, 5, 4, 3 ]
6
[ 3, 2, 4, 5 ]
7
[ 3, 2, 5, 4 ]
8
[ 3, 4, 2, 5 ]
9
[ 3, 4, 5, 2 ]
10
[ 3, 5, 2, 4 ]
11
[ 3, 5, 4, 2 ]
12
[ 4, 2, 3, 5 ]
13
[ 4, 2, 5, 3 ]
14
[ 4, 3, 2, 5 ]
15
[ 4, 3, 5, 2 ]
16
[ 4, 5, 2, 3 ]
17
[ 4, 5, 3, 2 ]
18
[ 5, 2, 3, 4 ]
19
[ 5, 2, 4, 3 ]
20
[ 5, 3, 2, 4 ]
21
[ 5, 3, 4, 2 ]
22
[ 5, 4, 2, 3 ]
23
[ 5, 4, 3, 2 ]
Process finished with exit code 0