全排列散列

详情说明可以参考其他文章,我这里是对康托展开 和 逆康托展开的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
odejs
ode.exe" D:	estCantor.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