康托展开

康托展开:康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩。设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。

公式:X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 

例如:123的全排列及其康托展开

 每个康拓值对应着这个排列在全排列中的位置。

代码实现:

int zz[50]={1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880} ;//假设n小于10 
int cnator(int* a,int n)
{
    int smaller=0,x=0;
    for(int i=0;i<n;i++)
    {
        smaller=0;
        for(int j=i+1;j<n;j++)
        {
            if(a[j]<a[i]) smaller++;
        }
        x+=zz[n-i+1]*smaller;
    }
    return x;
}

逆康托展开

思路:对于(1,2,3,4,5)给出61(它的康托展开是(3,4,1,5,2))。

61对4! %得13;/得2;所以a[5]=2,比第五位小的数有两个,所以第一位是3;

13对3! %得1;/得2;所以a[4]=1,比第四位小的数有一个,所以第二位是4;

1对2! %得1;/得0;所以a[3]=0,比第三位小的数有0个,所以第三位是1;

1对1! %得0;/得1;所以a[2]=1,比5第二位小的数有1个,所以第四位是5;

最后只剩2;

所以得到结果(3,4,1,5,2);

代码实现:

int zz[50]={1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
void decantor(int x,int n)
{
    int i,r,t;
    vector <int> v,a;
    for(i=1;i<=n;i++) v.push_back(i);
    for(i=n;i>=1;i--)
    {
        r=x%zz[i-1];
        t=x/zz[i-1];
        x=r;
        sort(v.begin(),v.end());
        a.push_back(v[t]);
        v.erase(v.begin()+t);
    }
}

参考文章:https://blog.csdn.net/wbin233/article/details/72998375

原文地址:https://www.cnblogs.com/2018zxy/p/9820601.html