STL源码:
在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}没有下一个元素。
原型:
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last
);
template<class BidirectionalIterator, class BinaryPredicate>
bool next_permutation(
BidirectionalIterator _First,
BidirectionalIterator _Last,
BinaryPredicate _Comp
);
// 第三个参数,默认比较顺序为小于。如果找到下一个序列,则返回真,否则返回假
源码:
template<class BidirectionalIterator>
bool next_permutation(
BidirectionalIterator first,
BidirectionalIterator last
)
{
if(first == last)
return false; //空序列
BidirectionalIterator i = first;
++i;
if(i == last)
return false; //一个元素,没有下一个序列了
i = last;
--i;
for(;;) {
BidirectionalIterator ii = i;
--i;
if(*i < *ii) {
BidirectionalIterator j = lase;
while(!(*i < *--j));
//while((*it)>=(*--j));
iter_swap(i, j);
reverse(ii, last);
return true;
}
if(i == first) {
reverse(first, last); //全逆向,即为最小字典序列,如cba变为abc
return false;
}
}
}
原理:
用自己理解的东西来讲,它其实使用到三个指针,但不是三个指针同时使用的,步骤是这样的:
- 先用first和second分别指向末尾的两个元素的位置,如果说(*first)< (*second)的话,我们就不往前了;否则就first和second分别往前一个
- 找到了之后,再用一个指针 j 来从尾部开始遍历,直到(*fisrt) < (*j)才结束;否则 j 一直往前遍历
- 交换 first 和 j 所指向的值
- reverse(second,end末尾指针)
为什么呢?首先我们得知道,排列存在某个元素一定比后面的元素都小的,找到这个值,这也是第一步的理由(这里是有可能出现重复字母的,不过没关系,判断条件是可以避免的);那为什么还要第二步呢?这里也是为了出现重复字母设置的(例子:34444这样),也就是说末尾到first之间的值一定都比first的小,那由于next_pre函数是寻找下一个排列,所以我们只要找到末尾到first中第一个比first大的值即可;注意:这里是要reverse(second,end末尾指针),因为这样才是下一个正确的排列,因为second到j的元素一定比j到second的元素大!!!好好想想!!!
#include <iostream>
# include <climits>
# include <bits/stdc++.h>
# include <string>
using namespace std;
bool next_per(string::iterator begin,string::iterator end){
if(begin==end) return false;
auto it = begin;
if(++it == end) return false;
it = end;
--it;
while(1){
auto pre = it;
--it;
if((*it)<(*pre)){
auto j = end;
--j;
while(1){
if((*it)<(*j)) break;
--j;
}
swap(*it,*j);
reverse(pre,end);
return true;
}
if(it==begin){
reverse(begin,end);
return false;
}
}
}
int main()
{
string s = "abc";
cout<<s<<endl;
while(next_per(s.begin(),s.end())){
cout<<s<<endl;
};
return 0;
}
//prev_permutation
#include <iostream>
# include <climits>
# include <bits/stdc++.h>
# include <string>
using namespace std;
bool next_per(string::iterator begin,string::iterator end){
if(begin==end) return false;
auto it = begin;
if(++it == end) return false;
it = end;
--it;
while(1){
auto pre = it;
--it;
if((*it)>(*pre)){
auto j = end;
--j;
while(1){
if((*it)>(*j)) break;
--j;
}
swap(*it,*j);
reverse(pre,end);
return true;
}
if(it==begin){
reverse(begin,end);
return false;
}
}
}
int main()
{
string s = "3321";
cout<<s<<endl;
while(next_per(s.begin(),s.end())){
cout<<s<<endl;
};
return 0;
}