排列组合(STL算法中next_permutation和prev_permutation剖析)

2 篇文章 0 订阅

STL提供了两个用来计算排列组合关系的算法,分别是next_permucation和prev_permutation。解决全排列问题。

首先我们必须了解什么是“下一个”排列组合,什么是“前一个”排列组合。考虑三个字符所组成的序列{a,b, c)。这个序列有六个可能的排列组合: abc,acb,bac,bca,cab,cba。

这些排列组合根据less-than操作符做字典顺序(按照升序排列)的排序。也就是说,abc名列第一,因为每一个元素都小于其后的元素。acb是次一个排列组合,因为它是固定了a(序列内最小元素)之后所做的新组合。同样道理,那些固定b(序列内次小元素)而做的排列组合,在次序上将先于那些固定c而做的排列组合。以bac和 bca为例,bac在 bca之前,因为序列ac小于序列ca。面对bca,我们可以说其前一个排列组合是bac,而其后一个排列组合是cab。序列abc没有“前一个”排列组合,cba没有“后一个”排列组合。

next_permutation

next_permutation ( )会取得〔 first,last)所标示之序列的下一个排列组合。如果没有下一个排列组合,便返回false;否则返回true。

next_permutation 算法过程:

首先,从最尾端开始往前寻找两个相邻元素,令第一元素为*i,第二元素为 *ii,且满足*i< *ii。找到这样一组相邻元素后,再从最尾端开始往前检验,找出第一个大于*i的元素,令为*j,将 i,j元素对调,再将 ii 之后的所有元素颠倒排列。此即所求之“下一个”排列组合。

e.g.以序列{0,1,2,3,4}为例,获得”下一个”排列组合。

输入序列{0,1,2,3,4}

  1. 第一元素为*i == 3,第二元素为 *ii == 4,且满足*i< *ii. 找到这样一组相邻元素(3 4)

  1. 从最尾端开始往前检验,找出第一个大于*i的元素,令为*j == 4

  1. i,j元素对调(*i == 4*j == 3),再将 ii 之后的所有元素颠倒排列

输出“下一个”排列组合{0,1,2,4,3};

e.g.以序列{0,1,2,4,3}为例,获得”下一个”排列组合。

输入序列{0,1,2,4,3}

  1. 第一元素为*i == 2,第二元素为 *ii == 4,且满足*i< *ii. 找到这样一组相邻元素(2 4)

  1. 从最尾端开始往前检验,找出第一个大于*i的元素,令为*j == 3

  1. i,j元素对调(*i == 3 *j == 2),再将 ii 之后的所有元素颠倒排列 (4 2-->2 4)

输出“下一个”排列组合{0,1,3,2,4};

代码测试求全排列问题:

#include<iostream>

using namespace std;

bool test_next_permutation(char* first, char* last)
{
    if(first == last) return false;
    char* i = first;
    ++i;
    if(i == last) return false;//只有一个元素
    i = last;                //i指向尾部
    --i;

    for(;;)
    {
        char* ii = i;
        --i;
        //以上,以确定一组相邻元素(升序)
        if(*i < *ii){ //如果前一个小
            char * j = last; //j指向尾部(尾元素下一个)
            while(!(*i < *--j));//由尾向前,找到比*i大的元素
            swap(*i,*j);  //交换i,j元素
            reverse(ii,last);//将ii后全部元素逆序排序
            return true;
        }
        if(i == first){  //进行首元素
            reverse(first, last);//全部逆向排序
            return false;
        }
    }
}
int main()
{
    char s[5] = "0123";
    do
    {
        cout<<s<<endl;
        
    }while(test_next_permutation(s,s+4));
    return 0;
}

prev_permutation

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值