知识点
获取下一个字典排列数
知识内容
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