C语言学习.docx
- 文档编号:29470085
- 上传时间:2023-07-23
- 格式:DOCX
- 页数:16
- 大小:24.83KB
C语言学习.docx
《C语言学习.docx》由会员分享,可在线阅读,更多相关《C语言学习.docx(16页珍藏版)》请在冰豆网上搜索。
C语言学习
编写递归程序有几个重要的原则可以遵循:
1. 要解决的问题可拆分为几个与原问题类似的子问题(子问题仍可拆分)。
2.每个子问题必须比原来问题的规模更小(即使小一号也行,当然如果能够迅速减小规模更好)。
3. 遇到足够小的子问题时就直接解决之,防止问题无限细分下去,也就是防止无限递归(递归终止条件很重要)。
先看一个最简单的递归程序,下面程序求整数n的阶乘:
intfactorial(intn)
{
returnn<=1?
1:
n*factorial(n-1);
}
所谓递归程序,就是程序在执行中又调用其自身,如上面函数factorial在其函数体内调用了函数factorial。
函数在每次被调用时都会生成一个包含自身局部变量的副本,即算是函数调用自身时也是如此。
递归程序主体主要由两部分构成:
一是递归执行部分,包含递归执行所需的条件;一是递归终止部分,含递归终止条件。
上面求阶乘的程序中把这两部分写在一行代码里面,把其分别抽出来便是:
intfactorial(intn)
{
if(n<=1)return1; // 递归终止体
returnn*factorial(n-1);//递归执行体
}
下面以几个经典算法问题的递归程序求解为例来分析编写递归程序中可以遵循的简单规则。
1.求正整数n所有可能的和式的组合,如给定正整数3,所有和加起来等于3的和式如下:
3=3+0
3=2+1
3=1+1+1
其中一个和式中的因子只能为自然数,因子允许重复出现。
这个问题是一个组合问题的变形,用递归程序实现如下(分析见注释):
#defineMAXSIZE50
staticintbuff[MAXSIZE];//存储和式因子组合的缓冲
///求当前和式中因子之和。
intSum(intbuff[],inti)
{
intsum=0;
for(intm=0;m<=i;m++)
sum+=buff[m];
returnsum;
}
///打印当前满足条件的和式。
voidprintFactor(intbuff[],inti,constintnumber)
{
intcount=0,m;
for(m=0;m<=i;m++)
printf("%4d",buff[m]);
if(number==buff[0])
printf("%4d",0);
printf("\n");
}
///递归求解所有和式组合。
///i-当前可选自然数的最大值。
///top-当前组合中因子个数。
///number-问题中要求解和式的正整数。
voiddivide(inti,inttop,intnumber)
{
for(intj=i;j>0;j--) //注意这里的循环条件,可以有效防止出现重复的组合
{
buff[top]=j;
if(number==Sum(buff,top)) //首先要确定递归中止条件
printFactor(buff,top,number);
elseif(number continue; if(top>=number) //和式中的因子不应该超过和的大小 continue; divide(j,top+1,number); //减小问题规模,继续递归 } return; } intmain() { inti,top=0; intnumber=8; printf("inputasoucenumber: "); scanf("%d",&number); i=number; divide(i,top,number); return0; } 2.给定正整数k,以及1-k共k个正整数的一个排列,假如是1,2,3,...,k,求所有和此排列“不相交”的排列。 所谓不相交,是指新的排列和已有排列在同一位置上的数都不相同。 如假设k=3,则其排列: 123和321是相交的,因为第二个位置上都是2;而排列123和312则不相交。 问题分析: 此问题是普通排列问题的变形,只要在排列问题的递归程序中加上位置的限制即可,程序实现如下,具体分析见注释。 constintN=5; intrange[9]={1,2,3,4,5,6,7,8,9};//预定义好位置的排列 ///判断当前选择的数j是否已经被使用。 boolselected(intj,int*buffer) { for(inti=0;i if(buffer[i]==j) returntrue; returnfalse; } ///求不相交排列。 ///i-当前排列的位置或者说当前排列元素个数。 ///buffer-存储当前排列的数组。 ///count-存储不相交排列的数目。 voidarrange(inti,int*buffer,int&count) { if(i==0) //递归终止条件 { for(intk=0;k cout< cout< count++; return; } for(intj=1;j<=N;j++) //循环挑选当前位置可以放置的数 { if(selected(j,buffer)) //判断当前选定的数是够已经用过 continue; buffer[i-1]=j; if(buffer[i-1]==range[i-1])//回溯的限制条件,同一位置的数不能和预定义的排列中相应位置的数相同 continue; arrange(i-1,buffer,count); //继续递归 } buffer[i-1]=0; //回溯,重新初始化当前位置 } intmain() { intbuffer[N]={0}; intcount=0; arrange(N,buffer,count); cout< return0; } 递归程序求解问题虽然优美简洁,但是和相应的非递归程序比较,随着问题规模的增大,程序的效率会逐渐下降,这也是递归程序的一大缺陷 尽管排列组合是生活中经常遇到的问题,可在程序设计时,不深入思考或者经验不足都让人无从下手。 由于排列组合问题总是先取组合再排列,并且单纯的排列问题相对简单,所以本文仅对组合问题的实现进行详细讨论。 以在n个数中选取m(0 1.首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。 2.从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。 很明显,上述方法是一个递归的过程,也就是说用递归的方法可以很干净利索地求得所有组合。 下面是递归方法的实现: ///求从数组a[1..n]中任选m个元素的所有组合。 ///a[1..n]表示候选集,n为候选集大小,n>=m>0。 ///b[1..M]用来存储当前组合中的元素(这里存储的是元素下标), ///常量M表示满足条件的一个组合中元素的个数,M=m,这两个参数仅用来输出结果。 voidcombine(inta[],intn,intm, intb[],constintM) { for(inti=n;i>=m;i--) //注意这里的循环范围 { b[m-1]=i-1; if(m>1) combine(a,i-1,m-1,b,M); else //m==1,输出一个组合 { for(intj=M-1;j>=0;j--)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 学习
![提示](https://static.bdocx.com/images/bang_tan.gif)