字符串的排列,递归输出
来源:互联网 发布:足球战术软件 编辑:程序博客网 时间:2024/06/11 04:23
(先稳定一下军心,下面所有代码都测试过,可以直接用,所以就没有截图,想看效果的可以自己运行一下)
1.全排列
全排列:字符以任意顺序排列,比如123的全排列是123,132,213,231,312,321。长度为n的字符串的全排列个数为n!个,下面是代码:
/*思路:s全排列是第一位与s[1~n-1]的全排列,所以每次交换第一位与** s中的某一位,然后递归求出s[1~n-1]的全排列。*/#include<iostream>#include <string>using namespace std;static int count=0;void Permutation(string s,int beg,int sLen){if(0==sLen) //这轮全排列结束{++count;cout<<s<<endl;return;}for (int i=0;i<sLen;++i){swap(s[beg],s[beg+i]); //将s中的每一位与第一位交换Permutation(s,beg+1,sLen-1); //排列s[1~n-1]swap(s[beg+i],s[beg]); //每一轮完后将交换后的字符还原}}int main(){string s;cout<<"请输入字符串:";cin>>s;int sLen=s.size();Permutation(s,0,sLen);cout<<endl<<"共"<<count<<"个"<<endl<<endl;return 0;}
void Permutation(string s,int beg,int end){if(beg==end-1) //这轮全排列结束{++count;cout<<s<<endl;return;}for (int i=beg;i<end;++i){swap(s[beg],s[i]);Permutation(s,beg+1,end);swap(s[i],s[beg]);}}
在上面的代码中,如果字符串中有重复的字符,就不能避免重复输出了。例如对于1213,n!=4!=24,如果考虑到避免重复输出,应该有4!/2!=12个。下面的代码是避免全排列中的重复输出:
/*思路:1.轮流选取s中的每位作为第一位。如果第i位字符在[0,i-1]这个区间内出现过,**就不再对其进行排列,因为把它放在第一位的所有排列在前面排列过了(就是代码中j作为循环变量的作用)。**2.把当前选取的这一位放入目标数组中。**3.用一个临时数组保存剩余的字符,并把其作为源。同时目标数组的地址下移一位,因为当前位已经排列好。*/#include<iostream>#include <string>using namespace std;static int count=0; //记录全排列个数char *result=new char[16](); //存放某个排列void Permutation(string strSource,char *strResult,int sLen){if(sLen==1) //这轮全排列结束{strResult[0]=strSource[0]; //只有一个字符++count; //strResult在递归的过程中是一次向后移一位的,所以字符串的首地址是resultcout<<result<<endl; return;}for (int i=0;i<sLen;++i){int j;for ( j=0;j<i&&strSource[j]!=strSource[i];j++); //判断当前字符是否在之前已经出现过if (j==i) //没有出现过{strResult[0]=strSource[i]; //把当前字符放在第一位//将除了当前位剩下的字符存入nextRecursion中,进入下一次递归string nextRecursion=strSource.substr(0,i)+strSource.substr(i+1,sLen-i-1); Permutation(nextRecursion,strResult+1,sLen-1); //strResult向后移一位,构造下个字符}}}int main(){string s;cout<<"请输入字符串:";cin>>s;int sLen=s.size();Permutation(s,result,sLen);cout<<endl<<"共"<<count<<"个"<<endl<<endl;return 0;}
2.排列
在第一节中讨论了字符串全排列的问题,在这一节讨论排列的问题。
排列:从长度为n的字符串中任意挑选m个元素以任意次序排列。全排列是n=m的特殊情况。
编程思路和上面的代码很像。最大的不同之处就是把结束时的情况放到了for循环里面,并且把return去掉了,这是为了保证所有的情况都能遍历到。还增加了一个参数k来记录已经取得的字符个数。
#include<iostream>#include <string>using namespace std;static int count=0; //记录全排列个数char *result=new char[16](); //存放某个排列//sLen是源字符串的长度,m是要取的字符个数,所以排列个数是A(sLen,m)//k为已经取得的字符个数void Permutation(string strSource,char *strResult,int sLen,int m,int k){for (int i=0;i<sLen;++i){int j;for ( j=0;j<k&&result[j]!=strSource[i];j++); //判断当前字符是否在之前已经出现过if (j==k) //没有出现过{if(k==m-1) //这轮全排列结束{strResult[0]=strSource[i]; ++count;//strResult在递归的过程中是一次向后移一位的,所以字符串的首地址是resultcout<<result<<endl; //return;}else{strResult[0]=strSource[i]; //把当前字符放在第一位//将除了当前位剩下的字符存入nextRecursion中,进入下一次递归string nextRecursion=strSource.substr(0,i)+strSource.substr(i+1,sLen-i-1); Permutation(nextRecursion,strResult+1,sLen-1,m,k+1); //strResult向后移一位}}}}int main(){string s;int m;cout<<"请输入字符串:";cin>>s;cout<<"请输入m:";cin>>m;int sLen=s.size();if(m<=sLen)Permutation(s,result,sLen,m,0);cout<<endl<<"共"<<count<<"个"<<endl<<endl;return 0;}
ps:为了和之前的代码保持连贯性,并且突出修改的重点(1.终止条件放到for循环中;2.去掉return),代码中的一些优化我都没有改。比如说,可以把if和esle中的strResult[0]=strSource[i]; 提出来;28行和29行的截取字符串是多余的,因为13行的代码已经判断重复问题了,所以28行和29行直接可以换成Permutation(strSource,strResult+1,sLen,m,k+1);
这个代码和上面的代码很像,这里可以好好体会一下这两个代码的不同之处。为了和数学中的排列定义A(n,m)相符,我把代码中的n换成了m,sLen相当于这里的n 。还需要说明的一点就是这段代码只能运用在无重复字符的字符串中,若有重复字符,会有重复输出。
0 0
- 字符串的排列,递归输出
- 【递归】输出一个字符串的所有排列
- JAVA递归和非递归输出字符串的全排列
- 递归复习,递归输出字符串的全排列
- 递归的应用,输出字符串的所有排列(java)
- 字符串的递归排列实现
- 字符串的全排列 递归
- 输出字符串的全排列
- 输出字符串的所有排列
- 输出字符串的全排列
- 输出字符串的全排列
- 输出字符串的全排列
- 输出字符串的所有全排列(递归法和非递归,非递归采用组合数学的字典序)
- 字符串-字符串的全排列-递归实现
- 字符串的排列输出 和组合输出
- 一个十分巧妙的递归,输出排列
- 递归输出char数组的所有排列
- 算法思维(递归)训练:输出字符串字符的全排列
- python 之 分割参数getopt
- ibatis简例1-用ibator插件自动生成sqlmap
- iOS中使用 Reachability 检测网络
- git 中文乱码问题
- ADB server didn't ACK 解决方法
- 字符串的排列,递归输出
- 2014年ENVI/IDL遥感应用与开发培训班-11月重庆站 开始报名了
- 字符指针数组和字符数组应用
- 从拉普拉斯矩阵说到谱聚类
- js生成0到9,0到10,1到10的随机数
- 第十周项目一 程序填充与阅读3 getchar()
- 比较全而且厉害的网站(作者很流弊的样子有木有!)
- Google C++ Style Guide中英对照(一)
- 基于MVC4+EF5+EasyUI技术实现通用权限管理系统(EpPlus、HignCharts、Reportviewer报表)