全排列—不含重复元素


初识全排列

定义:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
示例:对数组或者字符串进行全排列时,一般要求得出所有的排列结果。排列结果中的每个元素来自于原始数组,数量和内容与原始数组相同,只是元素的位置发生了改变。
比如对abc字符串进行全排列。则最后其全排列的结果为:abc,acb,bac,bca,cab,cba。
注:当对n各不相同的元素进行全排列时,其最终的排列结果有n!种。

全排列相关的算法

1.交换法

代码如下(示例):
注:在以下的代码中附加了一些c++的相关知识点,可以更好的帮助大家对下列代码的理解。

#include <bits/stdc++.h>
using namespace std;
int cnt=0;
void f(int p,string str,int n){
	if(p==n){
		cout<<str<<endl;
		cnt++;
		return;
	}
	//c++中相关sort函数的使用
	//bool compare(int i,int j){
	//	  return i<j;  //按照升序进行排列 
	//	  return i>j;  //按照降序进行排列 
	//}
	//sort(str.begin(),str.end(),compare); //str.begin()进行排列的起始位置,str.end()进行排列的结束位置,compare自定义的用于规定相关的排列方式,此处compare可以省略,当其省略后默认为升序排列 
	sort(str.begin()+p,str.end()); //按照相关的顺序进行输出 注:此处的起始位置+p是为了保证不影响进行交换了的字符
	for(int i=p;i<n;i++){
		swap(str[i],str[p]); //每个字符都有成为当前起始字符的机会,试探 
		f(p+1,str,n);  //对后面的字符进行全排列 
		swap(str[i],str[p]);  //返回初始状态,才能保证后面的交换是正确的,回溯 
	}
}
int main(){
	//c++中关于字符串的定义有char str[]="hello";  string str="hello"; 
	//c++若想要获取string类型的长度,可以使用str.length()  str.size()获取其相关的长度
	//当想要获取类型的长度时,可以使用sizeof(str)/sizeof(str[0])  注:使用此方法进行获取是需要注意'\0' 
	char str[10]="acb";
	int n = 3;
	int p = 0;
	f(p,str,n);
	cout<<cnt<<endl;  //输出全排列的类型数 
	return 0;
} 

2.抽取法

总体思路:抽取可用元素追加到新的数组中,相应的排列结果也在新的数组中。
代码如下(示例):
注:被抽取过的元素不能重复使用。

#include <bits/stdc++.h>
using namespace std;
int cnt = 0; //记录全排列含有多少种方式 
int vis[10] = {0}; //记录每个元素是否被访问过
void f(char str[],int n,char b[],int p){
	if(p==n){
		cout<<b<<endl;
		cnt++;
		return;
	}
	for(int i=0;i<n;i++){
		if(!vis[i]){  //若未被访问过,则将元素追加到新的数组 
			vis[i] = 1;   //将vis[i]置为1,表示其被访问过 
			b[p] = str[i];
			f(str,n,b,p+1);
			vis[i] = 0;  //返回到初始状态,保证后面的抽取是正确的 
		}
	}
} 
int main(){
	char str[10] = "abc";
	char b[10]="";
	int n=3;
	f(str,n,b,0);
	cout<<cnt<<endl;  //输出全排列的类型数 
	return 0;
}

3、使用next_permutation方法获取全排列

C++ STL中提供了std::next_permutation与std::prev_permutation可以获取数字或者是字符的全排列,其中std::next_permutation提供升序,std::prev_permutation提供降序。
说明:next_permutation,重复排列范围内的元素(第一,最后一个)返回按照字典序排列的下一个值较大的排列。
返回值:如果有一个更高的排列,它重复排列元素,并返回true;如果这是不可能的(因为它已经在最大可能的排列),它按升序排列所有元素,并返回false。
注:在用此方法进行全排列前,需要是相应的字符串变得有序。

#include <bits/stdc++.h>
using namespace std;
int main(){
	string str="bac";
	sort(str.begin(),str.end());
	int number=0;
	do{
		cout<<str<<endl;
		number++;
	}while(next_permutation(str.begin(),str.end()));
	cout<<number<<endl;
	return 0;
}

总结

在上述的全排列算法中,只适合于对不重复的元素进行全排列。
无论是交换法还是抽取法,在对元素的位置进行交换或追加中,其最后均需要回到初始状态,这样才能保证后面的交换或者追加正确。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
重复元素全排列流程图如下: 1. 首先将字符串按照字典序排序,以便后续判断重复元素。 2. 从第一个元素开始,依次与后面的元素交换位置,直到最后一个元素。 3. 在交换过程中,判断是否有重复元素即将被交换,如果有则跳过这次交换。 4. 交换完成后,将当前元素与下一个元素交换位置,重复步骤3。 5. 当交换到最后一个元素时,输出当前排列结果。 举个例子,对于字符串"abb"的全排列流程如下: 1. 首先将字符串按照字典序排序,得到"abb"。 2. 从第一个元素"a"开始,依次与后面的元素交换位置,得到"bab"和"bba"。 3. 在交换过程中,判断是否有重复元素即将被交换,发现"b"即将与"b"交换,跳过这次交换。 4. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 5. 交换到最后一个元素,输出当前排列结果"abb"。 6. 从第二个元素"b"开始,依次与后面的元素交换位置,得到"bab"和"bba"。 7. 在交换过程中,发现"b"即将与"a"交换,跳过这次交换。 8. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 9. 交换到最后一个元素,输出当前排列结果"abb"。 10. 从第三个元素"b"开始,依次与后面的元素交换位置,得到"abb"和"abb"。 11. 在交换过程中,发现"b"即将与"b"交换,跳过这次交换。 12. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 13. 交换到最后一个元素,输出当前排列结果"abb"。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值