STL之生成全排列:next_permutation & prev_permutation

本文详细介绍了C++ 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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值