康托展开与逆展开

一. 简单介绍:这是一种把每个数都不同的全排列映射为一个自然数的算法,也就是特殊的哈希函数。

康托展开:给定排列,算出在所有全排列中这个排列是第几大。

康托逆展开:给定第几大,求出排列。

二. 康托展开:

首先看有几个数小于最高位,然后这个数乘以数据规模-1的阶乘,累加到一个给定的值里面,然后第二位变为最高位,只向后找小于当前的值,一直到个位。

也就是说213456,找出比2小,有1个2*5!然后依次类推。

三. 康托逆展开:百度百科的例子很好

http://baike.baidu.com/link?url=d9PJo6Qp0C5IR4xIqsxp6JQaAD0aZ8bp-1CQfcYGpWpQu8RUwyp735BEW2yTwUpBYpBB1r23jhbsqF2yxmeMNa

四. 代码:

const int MAX_SIZE = 10;
int fac[MAX_SIZE + 1];

//计算 MAX_SIZE 的阶乘
void getFactorial()
{
    int i;
    fac[0] = 1;
    for(i = 1; i <= MAX_SIZE; i++){
        fac[i] = i*fac[i - 1];
    }
}

//康托逆展开:
//in为输入的数,ans为得到的排列.
void getArray(int in, int ans[])
{
//k用来保存剩下的数中当前第numOfMin + 1个数是多少。
//numOfMin表示在全部数中有几个数比当前数小。
//showed表示第几个数是否出现过。

    int i, j, numOfMin, k;
    bool showed[MAX_SIZE + 1] = {0};

    in--;
    for(i = 0; i < MAX_SIZE; i++){
        numOfMin = in / fac[MAX_SIZE - 1 - i];
        in = in % fac[MAX_SIZE - 1 - i];
        for(j = 0, k = 0; j <= numOfMin; k++)
                if(!showed[k])
                    j++;

        k--;
        ans[i] = k;
        showed[ans[i]] = true;
    }
}

//康托展开:
void getNumber(int &ans, int in[])
{
    int i, j, numOfMin;

    ans = 0;

    for(i = 0; i < MAX_SIZE - 1; i++){
        numOfMin = 0;
        for(j = i + 1; j < MAX_SIZE; j++){
            if(in[i] > in[j])
                numOfMin++;
        }
        ans += numOfMin*fac[MAX_SIZE - i - 1];
    }
    ans++;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值