next_permutation 实现

本文探讨如何利用STL中的next_permutation函数,解决快速求解下一个排列问题。通过对比传统的递归实现,讲解SGI STL源码中的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前实现的permutation一直是用数组(或者vector之类)的容器,然后递归出来的。面对要求快速求出next permutation的问题束手无策,今天看了STL中next_permution的实现,自己在没有看源码写一点吧。


#include <iostream>
#include <vector>
#include <string>

/* 算法的主要思想
    以数组 0 1 2 4 3 为例
    1. 从最末元素开始往前查找,找到第一对元素(第一个即为i,第二记为ii),
       使*i < *ii,在本例为元素对 2 4
    2. 从尾部开始往前查找,找出第一个大于i元素的值,记为j,此处为3
    3. 然后交换i和j的元素,再将ii后的元素(含ii)逆置,即可得next permutaioin
       例子的结果为 0 1 3 2 4
*/
template <typename T>
bool next_permutation (typename std::vector<T>::iterator first, typename std::vector<T>::iterator last)
{
    typename std::vector<T>::iterator i, ii, j;

    // 1. find the last pair of i and ii, let *i < *ii
    ii = last - 1;
    if (ii == first || first == last) // only 1 element or empty, done
        return false;

    i = ii - 1;
    for (; *i > *ii; )
    {
        ii = i;
        if (ii == first) // the next permutaion is not exist
            return false;
        -- i;
    }
    // found the pair

    // 2. find the j
    for (j = last - 1; j >= i && *j < *i; --j);

    // 3. swap i and j
    {
        T tmp = *i;
        *i = *j;
        *j = tmp;
    }

    // reverse ii - j
    while(j > ii)
    {
        T tmp = *j;
        *j = *ii;
        *ii = tmp;
        -- j;
        ++ ii;
    }

    return true;
}

template <typename T>
void show(const typename std::vector<T> &v)
{
    for (typename std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++ i)
    {
        std::cout << *i << " ";
    }
    std::cout << std::endl;
}

int main()
{
    int a[] = {0, 1, 2, 4, 3};
    std::vector<int> va(a, a + sizeof(a) / sizeof(a[0]));
    show<int>(va);

    if (next_permutation<int>(va.begin(), va.end()))
    {
        show<int>(va);
    }

    int b[] = {4, 3, 2};
    std::vector<int> vb(b, b + sizeof(b)/sizeof(b[0]));
    show<int>(vb);

    if (next_permutation<int>(vb.begin(), vb.end()))
    {
        show<int>(vb);
    }
    else
    {
        std::cout << "There is no next permutation!" << std::endl;
    }

    return 0;
}


SGI STL源码

// next_permutation and prev_permutation, with and without an explicitly 
// supplied comparison function.

template <class _BidirectionalIter>
bool next_permutation(_BidirectionalIter __first, _BidirectionalIter __last) {
  __STL_REQUIRES(_BidirectionalIter, _BidirectionalIterator);
  __STL_REQUIRES(typename iterator_traits<_BidirectionalIter>::value_type,
                 _LessThanComparable);
  if (__first == __last)
    return false;
  _BidirectionalIter __i = __first;
  ++__i;
  if (__i == __last)
    return false;
  __i = __last;
  --__i;

  for(;;) {
    _BidirectionalIter __ii = __i;
    --__i;
    if (*__i < *__ii) {
      _BidirectionalIter __j = __last;
      while (!(*__i < *--__j))
        {}
      iter_swap(__i, __j);
      reverse(__ii, __last);
      return true;
    }
    if (__i == __first) {
      reverse(__first, __last);
      return false;
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值