全排列散列 - (康托展开 和 逆康托展开)
详情说明可以参考其他文章,我这里是对康托展开 和 逆康托展开的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