题目来源:open judge1750全排列
全排列 1.0
#includeusing namespace std; void permutation(char a[],int m,int n){//对下标为m_n的字符数组段进行排列 if(m==n){//安排好了最后一位 for(int i=0;i<=n;i++){ cout<>str; int len=strlen(str); permutation(str,0,len-1); return 0; }
这种交换不能按照字典序进行全排列,为什么呢?
注意题目要求,“给定的字符串中的字母已经按照从小到大的顺序排列”
想要达到目的,每个字符轮流做第一位确保得到所有组合情况,但却没能
确保除第一位以外,剩余的各位仍然按照从小到大的顺序排列
在数组中直接将某位移到第一位,对剩余字符的处理却是 将第一位直接抛到后面不知道某位,则此次排序直接不能保证升序 之前一直被两个swap函数迷惑住,以为换回来是为了保证有序的,并不是,换回来是为了得到全排列组合后回到原来的最初始的序列 进行另外的全排列。
全排列 的内容有序与否,是第一次交换后的结果,极限思维,更新第一位后排列得到的 //123 321
第一种组合都是 仅仅更新第一位的序列,直接无序了
全排列 2.0
受到以上思想的启发,想要达到目的——每个字符轮流做第一位确保得到所有组合情况,并确保除第一位以外,剩余的各位仍然按照从小到大的顺序排列 。”注意题目要求,“给定的字符串中的字母已经按照从小到大的顺序排列”,那么直接维持原有序列就好,将某位字符移到第一位,剩余字符保持原序,在数组小标1——n的位置放好。
#includeusing namespace std; void swap1(char* a,int m,int i){//对下标为m_n的字符数组段进行排列,把a[i]提到首位m char temp=a[i]; // a[i]=a[i-1] a[i-1]=a[i-2] ……a[m+1]=a[m] for(int j=i;j>=m+1;j--){ a[j]=a[j-1]; } a[m]=temp; } void swap2(char *a,int m,int i){ char temp=a[m]; // a[m]=a[m+1] a[m+1]=a[m+2] ……a[i-1]=a[i] for(int j=m;j<=i-1;j++){ a[j]=a[j+1]; } a[i]=temp; } void permutation1(char a[],int m,int n){//对下标为m_n的字符数组段进行排列 if(m==n){//安排好了最后一位 for(int i=0;i<=n;i++){ cout<>str; int len=strlen(str); permutation1(str,0,len-1); return 0; }
在写函数permutation1 的时候,又发现一个不清楚的问题,就是 想把子函数中数组的形参 声明为数组的引用。
数组的形参声明方式有:
(一)、chara
对于这种形式,老师以前上课讲过,用字符串地址的方式声明字符串,在内存中开了一个足够大的缓冲区。
用char声明的是常量字符数组,所以之前用这种方式声明数组来做事总是出错。
当然啦,char*当作形参表示的是char a[]这个数组的地址,倒没有设计到main中数组的生命方式。
(二)、
想用数组的引用来声明形参,
奈何学识浅薄,涉及到了STL模板,此处应有表情包
C/C++对数组的引用
C++对数组的引用
C++对数组的引用(讨论的帖子)
之后再好好看看。
全排列 3.0
同思路2还有另一种实现方式,输出的序列用另一个数组存放,原数组元素从小到大排列的特性不去改变,只要利用这一点,从原数组中从前往后读取并存放在输出数组中,由于从前往后,输出数组读取到的元素一定是从小到大。
#includeusing namespace std; char str[10]; char output[10]; int isvisited[10];//对原数组中的元素设置是否进行过访问的标志,因为从 int len=0; void permutation3(int step){//分别确定output[step]的可能选取情况 if(step==len){//安排好了最后一位 // for(int i=0;i 字符串嘛 return; } else{ for(int i=0;i >str; len=strlen(str); permutation3(0);//对于output数组,从output[0]开始讨论每个元素可能的情况 return 0; }
对于output数组,从output[0]开始讨论每个元素可能的情况
output[step]=str[i];//一种组合情况中确定好了 output[step],
接下来该选取 output[step+1],考虑到进入permutation3(step+1)后又是从str[0]
开始由小到大选一个 (这种形式就相当于利用递归来实现一个len重循环了)
,一种组合情况中不可能选两个相同的元素,故对之前选取过的元素
需要设置isvisited 标志 ,没访问过的才进行选择。在一种组合没有完成之前,
str中的元素isvisited标记会逐渐全部变为1,每次需要选标记为0且 下标最小的元素
直到一次组合完成,再从后往前回溯,逐一将访问标志恢复为0,为下一次组合做准备
全排列 4.0
利用已有的next_permutation函数
介绍:next_permutation函数将按字母表顺序生成给定序列的下一个较大的排列,直到整个序列为降序为止。注意添加头文件#include
使用方法:next_permutation(数组头地址,数组尾地址);
若下一个排列存在,则返回真,如果不存在则返回假
若求上一个排列,则用prev_permutation
next_permutation(str,str+strlen(str))
数组下标从0开始噢,全排列的部分是,str[0]到str[len-1]
#includeusing namespace std; int main(int argc, char** argv) { char str[10]; cin>>str; int len=strlen(str); for(int i=0;i 至于next_permutation()的具体实现方式,参考以下(从别的大佬那儿搬来的):
STL具体操作之next_permutation和prev_permutation函数
#include#include using namespace std; int a[12]; bool turn(int a[] ,int n) { int k = n - 1; while(a[k-1] > a[k]) k--;//找到位置k //当k的位置是0的时候,说明整个排列时递减的,这个排列的字典序最大 if(k == 0) return false;//因此返回false k = k - 1; int t = n - 1; while(a[k] > a[t]) t--;//从后往前找到第一个大于a[k]的数字的位置 swap(a[k] , a[t]);//交换 reverse(a + k + 1, a + n);//翻转 return true;//返回true } int main() { int n; cin>>n; for(int i = 0 ; i



