在c++STL中提供了std::next_permutation与std::prev_permutation可以获取数字或者字符的全排列,每次函数调用获取下一次排列的结果,其中std::next_permutation提供升序、std::prev_permutation提供降序。
这是一个求一个排序的写一个排列的函数,可以遍历全排列,但要包含头文件 algorithm
(1) int 类型的next_permutation
int main()
{
int a[3];
a[0]=1;a[1]=2;a[2]=3;
do
{
cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<endl;
} while (next_permutation(a,a+3)); //参数3指的是要进行排列的长度
//如果存在a之后的排列,就返回true。如果a是最后一个排列没有后继,返回false,每执行一次,a就变成它的后继
}
输出:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
如果改成 while(next_permutation(a,a+2));
则输出:
1 2 3
2 1 3
只对前两个元素进行字典排序
显然,如果改成 while(next_permutation(a,a+1)); 则只输出:1 2 3
若排列本来就是最大的了没有后继,则next_permutation执行后,会对排列进行字典升序排序,相当于循环
int list[3]={3,2,1};
next_permutation(list,list+3);
cout<<list[0]<<" "<<list[1]<<" "<<list[2]<<endl;
//输出: 1 2 3
(2) char 类型的next_permutation
int main()
{
char ch[205];
cin >> ch;
sort(ch, ch + strlen(ch) );
//该语句对输入的数组进行字典升序排序。如输入9874563102 cout<<ch; 将输出0123456789,这样就能输出全排列了
char *first = ch;
char *last = ch + strlen(ch);
do {
cout<< ch << endl;
}while(next_permutation(first, last));
return 0;
}
//这样就不必事先知道ch的大小了,是把整个ch字符串全都进行排序
//若采用 while(next_permutation(ch,ch+5)); 如果只输入1562,就会产生错误,因为ch中第五个元素指向未知
//若要整个字符串进行排序,参数5指的是数组的长度,不含结束符
(3) string 类型的next_permutation
int main()
{
string line;
while(cin>>line&&line!="#")
{
if(next_permutation(line.begin(),line.end())) //从当前输入位置开始
cout<<line<<endl;
else cout<<"Nosuccesor\n";
}
}
int main()
{
string line;
while(cin>>line&&line!="#")
{
sort(line.begin(),line.end());//全排列
cout<<line<<endl;
while(next_permutation(line.begin(),line.end()))
cout<<line<<endl;
}
}
next_permutation 自定义比较函数
#include<iostream> //poj 1256 Anagram
#include<string>
#include<algorithm>
using namespace std;
int cmp(char a,char b) //'A'<'a'<'B'<'b'<...<'Z'<'z'.
{
if(tolower(a)!=tolower(b))
return tolower(a)<tolower(b);
else
return a<b;
}
int main()
{
char ch[20];
int n;
cin>>n;
while(n--)
{
scanf("%s",ch);
sort(ch,ch+strlen(ch),cmp);
do
{
printf("%s\n",ch);
}while(next_permutation(ch,ch+strlen(ch),cmp));
}
return 0;
}
例如:求1到9整数的全排列
1)
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
int m;
string s, a;
cin >> m;
for (int i = 0; i < m; i++)
{
cin >> a;
s += a;
}
cout << s << endl;
while (next_permutation(s.begin(), s.end()))
{
cout << s << endl;
}
return 0;
}
2)
#include<iostream>
using namespace std;
void output(char *buff, int len)
{
for (int i = 0; i < len; i++)
{
cout << buff[i] << " ";
}
cout << endl;
}
//思路:序列的全排列,就是从其中顺序调出一个元素作为第一个元素,将其与的元素做全排列
// 也就是把第一个元素,和后续的每一个元素做交换,把第一个元素以后的序列做全排列。
// 全排列的结果和第一个元素结合起来就是全排列的结果
// 其实就是递归
//参数说明:buff是总序列的头指针;n是总序列长度。这两个变量其实都是为了便利和打印方便
// walkindex是子序列的第一个元素位置,如果是第一次遍历,walkindex就是0,也就是全序列的全排列;walkindex为1就是从buff
// 的第二个元素开始的子序列的全排列
//说明:每个循环中有两个swap。第一个表示把子序列的头元素一次和第i个元素交换,然后生成子序列(walkindex后的序列)的全排列;然后恢复(再一次调用swap)
// 必须恢复,是因为思路是“顺序调出的每一个元素作为第一个元素”,如果子序列的全排列结束后不恢复,那下一次的for循环就拿不到正确的元素了。
// 比如原始序列为1 2 3 4 ,最外层遍历先把1和1交换(相当于没交换),得到子序列 2 3 4 的全排列,和1组成的6种结果
// 然后应该把1和2交换,2在第一个元素位置,子序列是1 3 4 ,,在计算这个子序列的全排列和2组成的6种结果
// 这时必须恢复1和2原来的顺序,才能让1和3交换做下一次的排序,也就是计算子序列1 3 4 后,必须再一次swap恢复出厂设置
void permutations(char* buff, int n, int walkindex)
{
if (walkindex == n)
{
output(buff, n);
return;
}
for (int i = walkindex; i < n; i++)
{
swap(buff[walkindex], buff[i]);
permutations(buff, n, walkindex + 1);
swap(buff[walkindex], buff[i]);
}
}
int main()
{
char anagrams[] = {'1','2','3','4','5','6','7','8','9' };
permutations(anagrams, 9, 0);
cout << "全排列后,anagrams会恢复到最初状态:" << endl;
output(anagrams, 9);
return 0;
}