template <class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator first, // iterator, like the C point
BidirectionalIterator last
)
{
if(first == last) return false; // no element
BidirectionalIterator i = first;
if(++i == last) return false; // only one element
i = last;
--i; // do not use i--, why?
for(;;) { // no statemnet loop, why do not use line 29 ?
BidirectionalIterator j = i; // do not use j=i--; why?
--i;
// find the last neighbor pair (i,j) which element i < j
if(*i < *j) {
BidirectionalIterator k = last;
while(!(*i < *--k)); // find last k >= i
iter_swap(i, k); // swap i and k
reverse(j, last); // reverse [j,last)
return true;
}
if(i == first) {
reverse(first, last); // current is in descending order
return false;
}
}
}
STL使用“!(*i < *j)”进行判断大小,若相等则继续寻找,这样就会跳过重复的元素,进而跳过重复的全排列(如:1,2,2; 和1,2,2)。有人会认为直接使用“*i>=*j”更清晰,对于int这种进本数据类型而言,这并没问题。然而,对于结构体甚至C++而言,元素是一个用户自定义数据类型,如何判断其大小?再退一步讲,如何进行排序?STL追求健壮、高效和精妙,对于用户自定义数据类型的排序,可以增加函数指针或者仿函数(Functional),只需要给定“a<b”的方法(如less(a,b))即可。如需求“a>b”可以转化成“b<a”;求“a==b”可以转化成“!(a<b) && !(b<a)”;求“a>=b”可以转化成“!(a<b)”。因此,一般自定义比较器只需要给定less()即可(对于C++而言,即重载操作符operator<)。
使用“--i;”而不是“i--;”,简言之,前者是先自减再使用,后者是先使用再自减。在这里虽然对结果也不影响,但是这两种实现方法还是有区别的。对于“i--;”来说,编译器首先会将i的值拷贝到临时变量中,然后对i进行自减,最后将临时变量返回;对于“--i”来说,编译器直接将i的值自减,然后将i的值返回。显然,“--i”只执行了两个指令操作,而“i--”执行了三个指令操作。所以能用“--i”的时候尽量不要使用“i--”。(PS:目前编译器已经十分智能了,对于上面的情况,即便写成“i--”仍然会按照“--i”进行编译,但请记住,不要指望任何版本的编译器都能帮你优化代码!)