直接上源码
template<typename _BidirectionalIterator, typename _Compare>
bool
__next_permutation(_BidirectionalIterator __first,
_BidirectionalIterator __last, _Compare __comp)
{
if (__first == __last) //没有元素,return false
return false;
_BidirectionalIterator __i = __first;
++__i;
if (__i == __last) //只有一个元素,不排列,return false
return false;
__i = __last;
--__i; //__i 指向最后一个元素
for(;;)
{
_BidirectionalIterator __ii = __i;
--__i; //从后往前遍历
if (__comp(__i, __ii)) //这里__comp函数以小于为例,直到找到一个a[i]<a[i+1]为止
{
_BidirectionalIterator __j = __last;
while (!__comp(__i, --__j)) //因为__i后面的序列一定是递减的,所以找到最小的大于__i指向的元素 交换即可
{}
std::iter_swap(__i, __j);
std::__reverse(__ii, __last,
std::__iterator_category(__first));
//同时,因为__i后的元素一定是递减的(不论交换前后) 故直接逆序即可,这也就得到了比当前序列大的最小排列
return true;
}
if (__i == __first) //若没找到a[i]<a[i+1] ,则此时表示已经到达了
{
std::__reverse(__first, __last,
std::__iterator_category(__first));
return false;
}
}
}
从源码中可以看出(没贴出),next_permutation的算法实现是基于__next_permutation实现的 故本文暂时只对该函数的实现进行解析。
需要注意的是,__first的实参是第一个元素,__second的实参是尾元素的后一位。
理解过程可以参看我加的注释
看源码是可以很快速地提升C++水平和算法能力的
总结全排列的算法思路就是:给定的某个排列,我们要找到比它大的最小排列。我们可以从后往前遍历该排列,找到第一个可以使当前排列变大的位置。然后再讲剩余部分,按从小到大排序即可。但是后面的序列一定是逆序的,故我们无需排序,直接reverse即可,时间复杂度可以优化到线性。
这个系列会不断更新,学习并解析c++源码,共同进步。