关于next_permutation函数与prev_permutation函数

在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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值