next_permutation算法【STL源码】

知识点

获取下一个字典排列数

知识内容

next_permutation功能是获取下一个排列数。这里澄清一点,给定一个序列,手动列出所有的排列和计算机列出所有的排列不一样。wiki给出的算法看得有点晕,大致意思是每次生成的下一个可以保证不重复。这个算法是有数学加持的。

从代码结构学到的,错误,异常都是一个循环先处理掉。

先后指针用i,ii,天然看出先后关系。

对于复杂的循环处理结构,可以不考虑控制条件和终止条件,做成一个死循环,内部用if判断做循环体,再设计一个if判断做终止条件也不错。

思想一定,算法实现就可以直观呈现算法原貌。怎么直观怎么来。

这里有几个模式,数组上双指针带条件循环找位置(for结构,只保留循环体),数组上单指针找大值(while结构,空循环体)

代码结构

template <class _BidirectionalIter, class _Compare>
bool __next_permutation(_BidirectionalIter __first, _BidirectionalIter __last,
                        _Compare __comp) {
  _STLP_DEBUG_CHECK(_STLP_PRIV __check_range(__first, __last))
  if (__first == __last)  //先处理掉异常
    return false;
  _BidirectionalIter __i = __first;
  ++__i;
  if (__i == __last)   //先处理掉异常,复用__i
    return false;
  __i = __last;
  --__i;

  for(;;) {
    _BidirectionalIter __ii = __i;  //for循环+i+ii,这种结构形成一个从尾向头的查找连续两个递增关系的东西,对应算法第一步找k
    --__i;
    if (__comp(*__i, *__ii)) {
      _STLP_VERBOSE_ASSERT(!__comp(*__ii, *__i), _StlMsg_INVALID_STRICT_WEAK_PREDICATE)
      _BidirectionalIter __j = __last;
      while (!__comp(*__i, *--__j)) {}  //从尾向头查找比i元素大的数,对应算法第二步找l
      iter_swap(__i, __j);  //这是第二步的交换,貌似k后就是最大的翻转数
      reverse(__ii, __last);  //k后到末尾进行翻转,对应算法第三步
      return true;  //翻转成功
    }
    if (__i == __first) {  //这是for循环的终止条件,如果查找两个递增关系的东西没找到,说明是最大的排列数,那需要进行翻转,循环进行,这个在算法说明提到过
      reverse(__first, __last);
      return false;
    }
  }

参考:

https://blog.csdn.net/u011231598/article/details/52396845

http://www.cppblog.com/yindf/archive/2010/02/24/108312.html

https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order

猜你喜欢

转载自blog.csdn.net/xiexie1357/article/details/88094465