next_permutation()会取得 [ first,last ) 所标示之系列的下一个排列组合。如果没有下一个排列组合,返回false,否则返回true。
算法过程:
首先从最尾端开始往前寻找两个相邻元素,令第一元素为 *i, 第二元素为 *ii ,且满足 *i < *ii 。找到这样一组相邻的元素后,再从最尾端开始往前检验,找出第一个大于 *i的元素,令为 *j, 将i,j元素对调,再将 ii 之后的所有元素颠倒排列。即求得下一个排列。
与next_permutation相反的函数是prev_permutation,算法过程:
首先从最尾端开始往前寻找两个相邻元素,令第一元素为 *i, 第二元素为 *ii ,且满足 *i > *ii 。找到这样一组相邻的元素后,再从最尾端开始往前检验,找出第一个小于 *i的元素,令为 *j, 将i,j元素对调,再将 ii 之后的所有元素颠倒排列。即求得下一个排列。
实例略。
next_permutation源码:
#include <cstdio>
#include <cstring>
template<class T> void reverse(T *l, T *r){
--r;
while( l<r ){
swap( *l++, *r-- );
}
}
/*
template<class T> bool next_permutation(T l, T r){
T p= r-1, q;
while( p!=l ){
q= p--;
if( *p < *q ){
T find= r-1;
while( *find <= *p ) --find;
swap( *find, *p );
reverse(q, r);
return 1;
}
}
reverse(l, r);
return 0;
}*/
template<class T>
bool next_permutation(T first, T last){
if( first == last ) return 0; // 特殊情况的处理,STL就是这样谨慎!
T i= first;
if( ++i==last ) return 0;
i= last;
--i;
while(1){
T ii= i;
--i; // i,ii锁定两个相邻的元素;
if( *i < *ii ){ // 如果前一个元素小于后一个元素;
T j= last;
while( ! ( *i < *--j ) ); // 由尾往前找,直到遇上比*i大的元素;
swap( *i, *j ); // 交换i,j位置上的两个元素;
reverse( ii, last ); // 将ii之后的元素全部逆向重排;
return 1;
}
if( i==first ){
reverse( first, last ); // 全部逆向重排,此时是最小字典序排列;
return 0;
}
}
}
template<class T> void swap(T &a, T &b){ T c=a; a=b; b=c; }
template<class T> int partition(T *a, int l, int r){
int index= l;
T key= a[index];
swap( a[index], a[r] );
for(int i=l; i<r; ++i){
if( a[i]<key )
swap( a[index++], a[i] );
}
swap( a[index], a[r] );
return index;
}
// a: [ l, r ];
template<class T> void Qsort(T *a, int l, int r){
if( l>=r ) return;
int index= partition(a, l, r);
Qsort(a, l, index-1);
Qsort(a, index+1, r);
}
int main(){
//char a[] = "cbad";
//char *l= a, *r= a+strlen(a);
int a[]= {3,3,3,2};
int *l= a, *r= a+4;
Qsort(a, l-a, r-a-1);
do{
//for(char *i=l; i<r; ++i) printf("%c", *i );
for(int *i=l; i<r; ++i) printf("%d ", *i);
puts("");
}while( next_permutation(l, r) );
}