C++ STL next_permutation函数
在STL中,除了next_permutation外,还有一个函数prev_permutation,两者都是用来计算排列组合的函数。前者是求出下一个排列组合,而后者是求出上一个排列组合。所谓“下一个”和“上一个”,书中举了一个简单的例子:对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。
next_permutation的函数原型如下:
对于第二个重载函数的第三个参数,默认比较顺序为小于。如果找到下一个序列,则返回真,否则返回假。
函数实现原理如下:
在当前序列中,从尾端往前寻找两个相邻元素,前一个记为*i,后一个记为*ii,并且满足*i < *ii。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。
代码实现如下:
1 template<class BidirectionalIterator> 2 bool next_permutation( 3 BidirectionalIterator first, 4 BidirectionalIterator last 5 ) 6 { 7 if(first == last) 8 return false; //空序列 9 10 BidirectionalIterator i = first; 11 ++i; 12 if(i == last) 13 return false; //一个元素,没有下一个序列了 14 15 i = last; 16 --i; 17 for(;;) { 18 BidirectionalIterator ii = i; 19 --i; 20 if(*i < *ii) { 21 BidirectionalIterator j = lase; 22 while(!(*i < *--j)); 23 24 iter_swap(i, j); 25 reverse(ii, last); 26 return true; 27 } 28 if(i == first) { 29 reverse(first, last); //全逆向,即为最小字典序列,如cba变为abc 30 return false; 31 } 32 } 33 }
上个例子
1 // next_permutation example 2 #include <iostream> // std::cout 3 #include <algorithm> // std::next_permutation, std::sort 4 5 int main () { 6 int myints[] = {1,2,3}; 7 8 std::sort (myints,myints+3); 9 10 std::cout << "The 3! possible permutations with 3 elements:\n"; 11 do { 12 std::cout << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n'; 13 } while ( std::next_permutation(myints,myints+3) ); 14 15 std::cout << "After loop: " << myints[0] << ' ' << myints[1] << ' ' << myints[2] << '\n'; 16 17 return 0; 18 }
The 3! possible permutations with 3 elements: 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 After loop: 1 2 3
具体应用可参考:字符串的排列