N个字符全排列的递归实现
来源:互联网 发布:网络红歌2016流行dj 编辑:程序博客网 时间:2024/06/05 09:36
递归算法的一个重要思想就是把规模大的问题向递归结束的条件靠拢。但是递归函数的原型和非终止条件下的递归怎么调用,是比较难的。
个人觉得,可以从递归执行的次数或结果的个数的计算来帮助怎么写递归的设计。如f(n)=f(n-1)+f(n-2)这种方式的递归,每个求f(n)就只要一个f(n-1),一个f(n-2).
而汉诺塔问题(http://blog.csdn.net/lin200753/article/details/27579481):f(n)=2*f(n-1)+1,则在处理第n次时,就要两次用于f(n-1)。
而全排列的递归也是类似的,f(n)=n*f(n-1),从而在第n次处理就要用于n次f(n-1),从而在非递归情况下就要用到一个长度可变的循环。循环的长度就是n。
(1)如果长度为1的字符串,则直接输出,它的全排序只有一个。
(2)len=2:如src[]=ab,则以a为排头,后面为b,则长度往(1)靠拢,输出src,
以b为排头,相当于将src[0]与src[1]交换得到src[]=ba,后面长度往(1)靠拢,输出src.
(3)len=3,如src[]=abc,则以a为排头,后面长度为2,往(2)靠拢,可以得到abc acb
以b为排头,相当于将src[0]与src[1]交换得到src[]=bac,后面长度为2,往(2)靠拢,可以得到bac bca
以c为排头,相当于将src[0]与src[2]交换得到src[]=cba,后面长度为2,往(2)靠拢,可以得到cba cab
len=4,,,,等情况类似,在以某个字符为排头结束后,要把src恢复到最原始的src,即要再进行一次交换。
这里先不考虑src中出现重复字符的情况。
从而若src的长度为n,则要进行src[0]与src[0],src[0]与src[1],......src[0]与src[n-1]进行n次交换。第一次交换相当于没有交换,只是以最开始的字符为排头,然后把长度减一进行递归处理。
#include "stdio.h"#include"string.h"#define DEBUG 1/*采用do..while(0)的方式*/#define SWAP(x,y) do{\int z=(x);\(x)=(y);\(y)=z;\}while(0)
/***全排列,有bug,不能有重复的字符。**/static int gen_allrang3(char *src,int s,int e,char *dest){int i;static count=0;if(s==e){strcat(dest,src);strcat(dest,",");printf("in gen3第%d个为:%s\n",++count,src);}else{ for(i=s;i<=e;i++){SWAP(src[s],src[i]);gen_allrang3(src,s+1,e,dest);SWAP(src[s],src[i]); } } return count;}/*对gen_allrang3进行封装*/int gen_allrang_API(char *src,char *dest){int len;int count;if(NULL==src||NULL==dest)return -1;len=strlen(src);count=gen_allrang3(src,0,len-1,dest);dest[strlen(dest)-1]='\0';return count;}int gen_allrang4(char *src,int s,int e){int i;static count=0;if(s==e){printf("in gen4第%d个为:%s\n",++count,src);}else{ for(i=s;i<=e;i++){SWAP(src[s],src[i]);gen_allrang4(src,s+1,e);SWAP(src[s],src[i]); }}return count;}void main(){ char src[]="abc"; char dest[1000]; int sum; *dest='\0'; //sum=gen_allrang3(src,0,strlen(src)-1,dest); sum=gen_allrang_API(src,dest); printf("count=%d,dest=%s\n",sum,dest);}
——————————————————————————————————————————————————————
而去除重复字符,之前有一种错误的想法:就是在src[s] 与src[i]交换的时候,若src[i]==src[s]就不交换,从而也不进入递归,即这个排头已经出现过了。之所以是错的,在于我们都是把src[s]与后面的交换,从而如src[]=abb,而src[0]!=src[1] src[0]!=src[2];
正确的方式是:当src[s],要与src[i],交换时,对s->i之间的字符进行查重,即在s->i之间(没有包括i),若已经出现了src[i],则不要交换。
/*若没有与src[e]重复的字符,则返回1,否则返回0*/int no_rep_to_e(char *src,int s,int e){int i;for(i=s;i<e;i++)if(src[i]!=src[e])continue;elsereturn 0;return 1;}int gen_allrang5(char *src,int s,int e){int i;static count=0;if(s==e){printf("in gen5第%d个为:%s\n",++count,src);}else{ for(i=s;i<=e;i++){ if(no_rep_to_e(src,s,i)) {SWAP(src[s],src[i]);gen_allrang5(src,s+1,e);SWAP(src[s],src[i]); } }}return count;}void main(){ char src[]="abb"; char dest[1000]; int sum; *dest='\0'; //sum=gen_allrang3(src,0,strlen(src)-1,dest); // sum=gen_allrang_API(src,dest); gen_allrang5(src,0,strlen(src)-1); }
in gen5第1个为:abb
in gen5第2个为:bab
in gen5第3个为:bba
Press any key to continue
若为1234,则相当于A44,=4*3*2*1=24种,这种递归不是字典序的。
in gen5第1个为:1234in gen5第2个为:1243in gen5第3个为:1324in gen5第4个为:1342in gen5第5个为:1432in gen5第6个为:1423in gen5第7个为:2134in gen5第8个为:2143in gen5第9个为:2314in gen5第10个为:2341in gen5第11个为:2431in gen5第12个为:2413in gen5第13个为:3214in gen5第14个为:3241in gen5第15个为:3124in gen5第16个为:3142in gen5第17个为:3412in gen5第18个为:3421in gen5第19个为:4231in gen5第20个为:4213in gen5第21个为:4321in gen5第22个为:4312in gen5第23个为:4132in gen5第24个为:4123 Press any key to continue
- 8.n个字符的全排列(递归实现)
- N个字符全排列的递归实现
- N个字符全排列的非递归实现
- 递归实现n个不同字符的所有全排列
- n个整数全排列的递归实现(C++)
- n个字符的全排列
- 求N个字符的全排列
- 求n个字符的全排列
- 递归实现的字符全排列
- n个字符全排列
- n个字符全排列
- 递归实现n个元素全排列(2)
- 递归实现输出n个整数的全排列和所有子集
- n个布尔变量值的全排列 递归算法
- 递归求n个元素的全排列
- 运用递归求n个元素的全排列
- 蓝桥杯 N个字符全排列
- 采用递归算法实现任意字符的全排列问题
- usb接口3g donggle调试步骤如下:
- const的用法
- URL-编码窗体数据无效
- java自动发送邮件到目标邮箱
- Linux多线程与同步
- N个字符全排列的递归实现
- function declaration isn't a prototype 如何解决
- 生命的柠檬茶
- OC 学习 字符串处理
- 关于KVM的相关理解
- Java通过POI读写Excel文件
- 金万维异速联再出大杀器 掀移动应用普及化年终热浪
- php 访问mysql
- 舌尖上的端午 粽子包满“学问”