全排列的递归与非递归

假如要求N个字符的全排列,N个字符的集合为S={C1, C2,...,Cn}

1.对于递归的情况,令去掉第i个字符后的集合为Si=S-{Ci},那么集合S的全排列

FullPermutation(S)为:

C1+FullPermutation(S1)

C2+FullPermutation(S2)

...

Cn+FullPermutation(Sn)

加号"+"表示字符连接,显然递归的结束条件是集合中只有一个字符的时候;

void  permutation( char *  str, int  l, int  s, char *  buf)
{
    
for ( int  i  =   0 ;i < l;i ++ )
    {
        
if (str[i]  !=   0 )
        {
            buf[s] 
=  str[i]; // 选入 
             char  t  =  str[i]  ;
            str[i] 
=   0 ;
            permutation(str,l,s
+ 1 ,buf);
            str[i] 
=  t;
        }
    }
    
if (s  ==  l)
    {
        buf[s] 
=   ' \0 ' ;
    
// cout<<buf<<endl;
    }
}
void  main()
{
    
char  y[] =  { ' a ' , ' b ' , ' c ' , ' d ' , ' r ' , ' g ' , ' e ' , ' x ' , ' y ' };
    
char  buf[ 128 ];
    permutation(y,
9 , 0 ,buf);

 

2.对于非递归,有不少的等价方式,其中之一想法如下(摘自 http://llfclz.itpub.net/post/1160/278490):

取第一个字符;

取第二个字符,可以放在第一个字符的左边或者右边,记为0和1;

取第三个字符,可以放在最左边,中间和最右边,记为0,1和2;

以此类推,第k个字符有k个位置可选

    类似二进位八进位那些数系转换关系。可以设计这样一个数, ...xyz, 其中个位数 z 是二进位的也就是放第二个数的两个位置十位数 y 是三进位的代表放第三个数字的三个位子然后百位数是四进位千位数是五进位的依以类推." 没错这样设计的话如果 0 表示放於最左面的话 "2021" 这个数就代表了排列五个元素 (abcde), 取一个 a, 然后第二个 b 放在 a 的右面成 ab, c 放到最右面成为 abc,  d 放到最左面成 dabc; 最后 e 放到中间去成为 daebc. 至於 "2021" 这个特别的设计的数可以用2*5+ 0*4 + 2*3 + 1*2 这样的计算来映对到自然数的数列上去。 

    如求 4 个数的 4! = 24 个排列 18 个排列可以这样求得, 18  2, 余数是 0, 所以第二个数放在第一个数的左面然后商 9 再除 3, 余数 0, 所以第三个数於在头两个数的最左最后 3 除以 4, 余数是 3, 因此第四个数要放在前三个数的第 4 个空位也就是最右面。

 

以下是非递归的代码(留着以后再用...)

//全排列
void FullPermutation(const char *array, int size)
{
    int i = 1;
    int n = 1;
    char *pBuf = new char[size+1];
    for (; i <= size; i++)
    {//算size的阶乘
        n *= i;
    }

    for (i = 0; i < n; i++)
    {
        print(i, array, size, pBuf);
    }
    delete []pBuf;

}

 //打印当前idx对应的序列
 //为了避免内存new过来delete过去的,就把缓存当成参数了....
 void print(int idx, const char *array, int size, char *&pBuf)
{
    int i, j, k;
    pBuf[0] = array[0];
    for (i = 2; i <= size; i++)
    {
         k = idx%i;
         for (j = i-1; j > k; j--)
        {//为第i个字符腾出空来
              pBuf[j] = pBuf[j-1];
        }
        pBuf[k] = array[i-1];
        idx /= i;
    }
    pBuf[size] = '\0';
    cout << pBuf << endl;
}

转载于:https://www.cnblogs.com/davidluo/articles/1802838.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值