STL之生成全排列:next_permutation & prev_permutation

源码剖析:

next_permutation:

函数实现原理如下:

在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。


template<typename _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;  //令__j指向尾端
            while (!(*__i < *--__j))   //由尾端往前找,直到遇到比*__i大的元素
            { }
            std::iter_swap(__i, __j);  //交换__i,__j
            std::reverse(__ii, __last);  //将 __ii 之后的元素全部逆向重排
            return true;
        }
        if (__i == __first)   //进行到最前面了
        {
            std::reverse(__first, __last);  //全部逆向重排
            return false;
        }
    }
}

prev_permutation:

template<typename _BidirectionalIterator>
bool prev_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 (*__ii < *__i)
	    {
            _BidirectionalIterator __j = __last;
            while (!(*--__j < *__i))
            { }
            std::iter_swap(__i, __j);
            std::reverse(__ii, __last);
            return true;
	    }
        if (__i == __first)
	    {
            std::reverse(__first, __last);
            return false;
	    }
	}
}


测试如下: (可使用string 或 char,int 数组)
#include <cstdio>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;

int main()
{
    int a[10],b[10];
    int n;
    puts("输入数字个数:");
    scanf("%d",&n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d",&a[i]);
        b[i] = a[i];
    }

//    sort(a,a+n); 
    puts("prev_permutation:");
    while(prev_permutation(b,b+n))
    {
        for(int i = 0; i < n; i++)
        {
            printf("%d ",b[i]);
        }
        printf("\n");
    }
    puts("next_premutation:");
    while(next_permutation(a,a+n))
    {
        for(int i = 0; i < n; i++)
        {
            printf("%d ",a[i]);
        }
        printf("\n");
    }
}
string:

#include <iostream>
#include <algorithm>
#include <string>
 
using namespace std;
 
int main()
{
    string str;
    cin >> str;
    sort(str.begin(), str.end());
    cout << str << endl;
    while (next_permutation(str.begin(), str.end()))
    {
        cout << str << endl;
    }
    return 0;
}

对于第三个参数:

对于第二个重载函数的第三个参数,默认比较顺序为小于。如果找到下一个序列,则返回真,否则返回假。

comp
Binary function that accepts two arguments of the type pointed by  BidirectionalIterator, and returns a value convertible to  bool. The value returned indicates whether the first argument is considered to go before the second in the specific  strict weak ordering it defines.
The function shall not modify any of its arguments.

This can either be a function pointer or a function object.

plusplus:

重排列之后的序列为最小字典列(对于prev反之);

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// next_permutation example
#include <iostream>     // std::cout
#include <algorithm>    // std::next_permutation, std::sort

int main () {
  int myints[] = {1,2,3};

  std::sort (myints,myints+3);

  std::cout << "The 3! possible permutations with 3 elements:\n";
  do {
    std::cout << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n';
  } while ( std::next_permutation(myints,myints+3) );

  std::cout << "After loop: " << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n';

  return 0;
}

Output:
The 3! possible permutations with 3 elements:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
After loop: 1 2 3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值