每天一个算法: 全排列算法

8 篇文章 0 订阅

全排列算法:给出一个有n个元素的集合,求出这个集合所有可能的排列。
一、 递归的方法

void  permutation(char *arr, int k , int m){
     if(k == m){
        for(int i =0; i< m; i++){
            cout<<arr[i];    //输出排列                    
        }
        cout<<endl;
     }else {
        for(int j = k; j < m; j++){
            swap(arr[j],arr[k]);
            permutation(arr,k+1,m);
            swap(arr[j],arr[k]);
         }
     } 
}

二、 STL实现
有时候递归的效率使得我们不得不考虑除此之外的其他实现,很多把递归算法转换到非递归形式的算法是比较难的,这个时候我们不要忘记了标准模板库已经实现的那些算法,这让我们非常轻松。STL有一个函数next_permutation(),它的作用是如果对于一个序列,存在按照字典排序后这个排列的下一个排列,那么就返回true且产生这个排列,否则返回false。注意,为了产生全排列,这个序列要是有序的,也就是说要调用一次sort。STL提供的next_permutation()函数大大简化了编程,这是一个十分有用的函数。此外与之对应的还有prev_permutation()函数,可以得到上一个全排列。这让全排列实现起来很简单,我们看一下代码:

    void permutation(char* str,int length)  
{  
    sort(str,str+length);  
    do  
    {  
        for(int i=0;i<length;i++)  
            cout<<str[i];  
        cout<<endl;  
    }while(next_permutation(str,str+length));  

}  

三、有一定约束条件的全排列
对数1,2,3,4,5要实现全排序。要求4必须在3的左边,其它的数位置随意。思路:首先使用上面的2种方法之一实现全排列,然后对全排列进行筛选,筛选出4在3左边的排列。

void permutation(int* a,int length)  
{  
    int i,flag;  
    sort(a,a+length);  
    do  
    {  
        for(i=0;i<length;i++)  
        {  
            if(a[i]==3)  
                flag=1;  
            else if(a[i]==4)    //如果3在4的左边,执行完代码,flag就是2  
                flag=2;  
        }  
        if(flag==1)          //如果4在3的左边,执行完代码,flag就是1  
        {  
            for(i=0;i<length;i++)  
                cout<<a[i];  
            cout<<endl;  
        }  
    }while(next_permutation(a,a+length));  

}

四: next_permutation的原理
next_permutation()函数是按照字典序的顺序得出比当前排列大,且最靠近当前排列的下一个排列。
函数实现原理如下:在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。代码如下:

template<class BidirectionalIterator>  
bool next_permutation(  
      BidirectionalIterator first,   
      BidirectionalIterator last  
)  
{  
    if(first == last)  
        return false; //空序列  

    BidirectionalIterator i = first;  
    ++i;  
    if(i == last)  
        return false;  //一个元素,没有下一个序列了  

    i = last;  
    --i;  

    for(;;) {  
        BidirectionalIterator ii = i;  
        --i;  
        if(*i < *ii) {  
            BidirectionalIterator j = last;  
            while(!(*i < *--j));  

            iter_swap(i, j);  
            reverse(ii, last);  
            return true;  
        }  

        if(i == first) {  
            reverse(first, last);  //全逆向,即为最小字典序列,如cba变为abc  
            return false;  
        }  
    }  

}  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值