全排列—不含重复元素

    科技2022-08-17  118

    文章目录

    初识全排列全排列相关的算法1.交换法2.抽取法3、使用next_permutation方法获取全排列 总结


    初识全排列

    定义:从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; }

    总结

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

    Processed: 0.008, SQL: 10