资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,#,项目3,项目3,1,技能目标,会画程序的流程图或N-S结构图,会用if-else实现分支结构和多分支结构的程序设计,会用条件运算符进行分支结构的程序设计,会用switch语句实现多分支结构的程序设计,会用for语句、while语句、do-while语句进行循环结构程序设计,会用break语句和continue语句,技能目标会画程序的流程图或N-S结构图,2,知识目标,掌握if-else语句的用法,掌握条件运算符的使用,掌握switch语句的用法,掌握for语句、while语句和do-while语句的使用,掌握循环的签套使用,掌握break和continue语句的使用,知识目标掌握if-else语句的用法,3,项目任务与解析,本项目实现班级学生成绩管理系统中用if语句实现菜单的选择执行、用switch语句实现菜单的选择执行、用循环语句实现主菜单的选择执行。,本项目包含下面几个任务:,任务4:用if语句实现菜单的选择执行, 任务5:用switch语句实现菜单的选择执行, 任务6:用循环语句实现主菜单的选择执行,项目任务与解析本项目实现班级学生成绩管理系统中用if语句实现,4,主要内容,3.1 任务4:用if语句实现菜单的选择执行,3.2 必备知识与理论,3.3 扩展知识与理论,3.4 任务5:用switch语句实现菜单的选择执行,3.5 必备知识与理论,3.6 扩展知识与理论,3.7 任务6:用循环语句实现菜单的选择执行,3.8 必备知识与理论,3.9 扩展知识与理论,主要内容3.1 任务4:用if语句实现菜单的选择执行,5,3.1,任务4:用if语句实现菜单的选择执行,1. 问题描述,对显示的菜单,选择要执行的菜单序号,并显示要执行的菜单名。,2. 具体实现,P41程序,3. 知识分析,在多数情况下顺序结构的程序是很少的,一般还包括分支和循环结构。分支结构还包括if-else结构和switch结构。我们首先来学习分支结构,在学习分支结构前了解一些算法的概念,关系运算符和逻辑运算符的使用。,3.1 任务4:用if语句实现菜单的选择执行1. 问题描述,6,3.2,必备知识与理论,3.2.1 算法的概念,1.算法,算法就是程序处理问题的步骤与方法。,1976年瑞士计算机科学家Niklaus Wirth提出了一个著名的公式:,算法 + 数据结构 = 程序,3.2必备知识与理论3.2.1 算法的概念,7,2. 算法的特性,简单地说,算法就是进行操作的方法和操作步骤。例如,菜谱实际上是做菜肴的算法,乐谱实际上是演奏的算法,计算机程序是用某种程序设计语言描述的解题算法。通常认为算法有如下一些性质:,(1)有穷性,一个算法要在有限的步骤内解决问题(这里所说的步骤是指计算机执行步骤)。计算机程序不能无限地运行下去(甚至不能长时间地运行下去),所以一个无限执行的方法不能成为程序设计中的“算法”。,(2)确定性,确定性具有两重意义:一是所描述的操作应当具有明确的意义,不应当有歧义性。例如,不能发出这样的操作指令:“执行一个算术操作”。因为它既没有指出算术操作的类型,也没有指出操作数。,确定性的另一重意义:, 操作作序列只有一个初始动作,序列中每一动作仅有一个后继动作;, 序列终止表示问题得到解答或问题没有解答,不能没有任何结论。,2. 算法的特性,8,(3)有零个或多个输入,输入就是从外界取得必要的信息。一个算法可以有零个或多个输入,例如:输入一个年份,判断其是否是闰年。同时一个算法可以没有输入,例如:计算出5!是多少。,(4) 有一个或多个输出,算法的目的就求解,“解”就是我们想要得到的最终结果。输出是同输入有着某些特定关系的量。一个算法得到的最终结果就是输出。没有输出的算法是没有意义的。,(5) 可执行性,一个算法应当是可以由计算机执行的,算法中描述的操作都是可以通过计算机的运行来实现。,(3)有零个或多个输入,9,3.2.2 算法的表示方法,1. 自然语言表示算法,自然语言是相对于计算机语言而言的,是指人们在日常生活中使用的语言,如汉语、英语等。对于某些程序员来说,自然语言通俗易懂。但是,对于规模大、复杂的算法,使用自然语言来描述,往往很冗长,不直观,而且容易发生歧义。比如对于以下这句话:如果A大于B,就给它加1。在理解时就可能出现歧义,是给A加1?还是给B加1。,对于以上的一段话,如果我们用C语言进行编程则为:,if(AB),A=A+1;,正是由于自然语言描述算法具有的缺陷,所以在程序设计中很少有人使用。,3.2.2 算法的表示方法 ,10,2. 传统流程图表示法,用一些图框表示各种操作,用线表示这些操作的执行顺序。我国国家标准GB 152689中推荐的一套流程图标准化符号,它与国际标准化组织ISO提出的ISO流程图符号是一致的。图3-1为其中常用的一些符号。,2. 传统流程图表示法,11,过程,判断,数据,预定义过程,起止,流程线,连接,注释,图3.2 常用的流程图标准化符号,过程判断数据预定义过程起止流程线连接注释图3.2 常用,12,平行四边形表示数据,其中可注明数据名称、来源、用途或其它的文字说明。,处理矩形表示各种处理功能。例如,执行一个或一组特定的操作,从而使信息的值、信息形式或所在位置发生变化。矩形内可注明处理名称或其简要功能。,预定义过程带有双竖边线的矩形,表示已命名的处理。该处理为在另外地方已得到详细说明的一个操作或一组操作。例如库函数或其它已定义的函数等。矩形内可注明特定处理名称或其简要功能。,判断菱形表示判断。菱形内可注明判断的条件。它只有一个入口,但可以有若干个可供选择的出口,在对定义的判断条件求值后,有一个且仅有一个出口被选择。求值结果可在表示出口路径的流线附近写出。,流线直线表示执行的流程。当流程自上向下或由左向右时,流程线可不带箭头,其它情况应加箭头表示流程。,端点。扁圆形表示转向外部环境或从外部环境转入的端点符。例如,程序流程的起、始点。,注解。注解是程序的编写者向阅读者提供的说明。注解符由纵边线构成,它用虚线连接到被注解的符号或符号组上。,平行四边形表示数据,其中可注明数据名称、来源、用途或其它的文,13,图3-2(a)、(b)、(c)中的虚线框,分别为用流程图表示的三种基本流程控制结构。,S1,S2,S3,P,S1,S2,真,假,P,S2,假,真,(a)顺序结构,(b)选择结构,(c)重复结构,图3-2,用流程图描述的三种基本结构,图3-2(a)、(b)、(c)中的虚线框,分别为用流,14,例3-1 用流程图描述从三个数中取最大数的算法。,从三个数中取最大数的算法思路是:假定这三个数是a,b,c,则首先可以比较a,b两数,从中选大者;然后再用这个大数与数c比较,从中取大者。这时得到的大数,就是三个数中的最大数。这个算法用流程图描述如图3-3(a)所示。,通常,求解一个问题的算法不是唯一的。例如图3-3(b)也是一个三数中取大的算法。它的基本思路是,先设max=第一个数,然后依次输入i个数,每输入一个数,与max比较一次,把大的放入max中。当输完i个数时,max中存放的就是这i个数中的最大数。这里,i是一个计数器,用于统计输入数的个数,所以每输入一个数,要执行一次自增操作。这个算法与图3-3(a)所示算法的不同在于:,算法结构不同:图3-3(a)所示算法采用了两个选择结构,而图3-3(b)所示算法采用了一个循环结构和一个选择结构。,算法的灵活性不同:图3-3(b)中的算法可以用来求任意个数中的最大数。,例3-1 用流程图描述从三个数中取最大数的算法。,15,a=b,输入a,b,c,max=a,真,假,max=b,max=c,真,假,输出max,输出c,开始,结束,i=max,max=n,(a)一个三数中取大的算法,(b)另一个三数中取大的算法,图3-3 三数中取大算法的流程图描述,a=b输入a,b,cmax=a真假max=bmax=c真,16,3.,用N-S流程图表示算法,灵活的流线是程序中隐藏错误的祸根。针对这一弊病,1973年美国学者I.,Nassi,和,B. Shneiderman,提出了一种无流线的流程图,称为,N-S,图。它的三种基本结构如图,3-4,所示。,N-S图的每一种基本结构都是一个矩形框,整个算法可以像堆积木一样堆成。其中,,(a)为三个操作组成的顺序结构;(b)为二分支的选择结构;(c)为当型重复结构,即当命题P 为“真”时,就重复执行S。,3. 用N-S流程图表示算法,17,S1,S2,S3,P,S1,S2,当P,S,假,真,(c)循环结构,(a)顺序结构,(b)选择结构,图3-4 用,N-S图描述三种基本流程结构,S1S2S3PS1S2当PS假真(c)循环结构(a)顺序结构,18,图3-5(a)、(b)给出了用与图3-3(a)、(b)流程图对应的N-S图。,a=b,max=a,max=b,输入a,b,c,假,真,max=c,输出max,输出c,真,假,当i=max,max=n,真,假,输入n,初始化:max=0,i=1,输出max,(a)采用选择结构,(b)采用循环结构,图3-5,三数中取大算法的N-S图描述,图3-5(a)、(b)给出了用与图3-3(a)、(b,19,3. 用伪码表示算法,伪代码(pseudo code)是用介于自然语言与计算机语言之间的文字符号算法描述的工具。它无固定的、严格的语法规则,通常是借助某种高级语言的控制结构,中间的操作可以用自然语言(如中文或英文),也可以用程序设计语言,或使用自然语言与程序设计语言的混合体。一般专业人员习惯用伪代码进行算法描述。,下面是与图3-3相对应的三数中取大算法的伪代码描述。,(1)与图3-3(a)相对应的三数中取大算法的伪代码描述:,输入a,b,c;,if(a=b),max=a;,else,max=b,if(max=c),输出max;,else,输出c;,3. 用伪码表示算法输入a,b,c;,20,(2)与图3-3(b)相对应的三数中取大算法的伪代码描述:,初始化:mac=0,i=1;,当(i=max),max=n;,),输出max;,(2)与图3-3(b)相对应的三数中取大算法的伪代码描述:初,21,3.2.3,结构化程序设计,结构化程序设计的基本思路是:把一个复杂的问题的求解过程分阶段进行,每个阶段处理的问题都控制在人们容易理解的范围之内。采取以下的方法保证得到结构化的程序:,自顶向下;,逐步细化(求精);,模块化设计;,结构化编码。,3.2.3 结构化程序设计,22,结构化程序具有如下的特征:,一个程序单元由顺序、分支和循环这三种基本结构组成;,一个大的程序由若干个不同功能的小模块组成;,每一个小模块只有一个入口和一个出口;,结构化程序具有如下的特征:,23,3.2.4 命题与C语言中的逻辑值,对选择结构、循环结构,流程的改变都是由判断决定的,即需要根据判断决定选择,根据判断决定是否循环以及循环的结束。通常,判断是针对命题的“真”、“假”进行的。例如,下面是一些命题:, (行驶中)前面的交通信号灯是红色的。, 今天下雨。, ab。, 如果a不能被b,整除。,这些命题的值都只能是一个逻辑(布尔)值:“真”或“假”。,早期的C语言不提供专门的逻辑(布尔)类型,规定用非0值表示“真”,用0值表示“假”。,在C99中,增加了_Bool类型,并增加了头文件,在其中定义了宏bool、true和false,用true存储1,用false存储0。,3.2.4 命题与C语言中的逻辑值,24,3.2.5 关系运算与关系表达式,1. C语言的关系运算符,关系运算是指对两个表达式值的大小比较。C语言中提供有如下6个关系运算符:,(大于) =(大于或等于)(小于),=(小于或等于) =(等于)!=(不等于),后两个(=和!=)的优先级小于前4个,但它们都低于算术运算符,高于赋值运算符,并且它们结合方式都是从左向右的。,3.2.5 关系运算与关系表达式 ,25,2. 关系表达式,用关系运算符将两个表达式(可以是算术表达式、关系表达式,逻辑表达式,赋值表达式,字符表达式等)连接起来的表达式,称为关系表达式。,关系表达式的值只有两个:关系表达式成立,即为“真”(通常为1);关系表达式不成立,即为“假”(0)。,2. 关系表达式,26,3.2.6 逻辑运算与逻辑表达式,1. 逻辑运算符与优先级,C语言有三个逻辑运算符,它们是:,& (逻辑与) |(逻辑或) !(逻辑非),&和|是二元运算符,结合方向为自左至右;!为一元运算符, 结合方向为自右至左。,!的优先级高于&,&的优先级高于|。,&和|的优先级低于关系运算符,而!的优先级高于关系运算符。,2. 逻辑表达式,用逻辑运算符将关系表达式或逻辑量连接起来的表达式就 是逻辑表达式,逻辑表达式的值应该是一个逻辑量“真”或“假”。,27,逻辑运算中有很多有趣的规律,这种规律称为短路原则。,1. 在一个&表达式中,若&的一端为0,则不必再计算另一端,该表达式的值肯定为0(在C语言中由于&是从左向右结合的,所以只考虑左端,即当&号的左端为0时,不再计算其右端),可以把它记为:,0 & a=0,2. 在一个|表达式中,若|的一端为1,则不必计算另一端,该|表达式的值必为1。现把它记为:,1|a=1,诸如此类关于表达式的值的规律有如下一些:,0|a=a1&a=a1|a=1,0&a=0 a|!a=1 0&!a=0,以及,a|a=aa&a=a!(a|b)=!a&!b,!(a&b)=!a|!b !(!a)=a,记住这些规律,能使复杂的逻辑运算简化、清晰。,28,3.3,扩展知识与理论,选择型程序描述了求解规则:在不同的条件下所应进行的相应操作。,3.3.1,if(表达式) 语句,这种语句的结构是:,if (表达式),语句,它的执行流程是,当表达式的值为真时,执行“语句”,否则执行if语句后面的语句。,3.3 扩展知识与理论选择型程序描述了求解规则:在不同的条件,29,例3-4 输入三个数a,b,c,要求按由小到大的顺序输出。,我们只要把最小的数放到a上:先将a与b进行比较,如果ab则将a与b的值进行交换,然后再用a与c进行比较,如果ac则将a与c的值进行交换,这样能使a最小。对剩下的两个数,从小到大排序就容易了,该程序的N-S结构图如右图所示。,例3-4 输入三个数a,b,c,要求按由小到大的顺序输,30,3.3.2 ifelse结构,ifelse构造了一种二路分支的选择结构,它的格式如下:,if (表达式),语句1,else,语句2,这里,语句1和语句2就是两路分支。执行这个结构,首先对表达式进行判断,若为“真”(非零),就执行if分结构(语句1);否则(值为0),就执行else分结构(语句2)。,3.3.2 ifelse结构,31,例3-5 求一个数的绝对值。,设有任意数x,它的绝对值为,判断内容:x0是否成立。,两路分支:x=x (当x0) ; x= -x (当x0 ),C函数如下:,double abstr (double x),if (x0.0),x=-x;,else,x=x;,return (x);,例3-5 求一个数的绝对值。double abstr (d,32,下面是函数abstr被调用执行的情况:,#include ,int main(void),double a, abstr (double a);,printf (Enter real number a please:);,scanf (%1f,printf (abstr(%1f)=%1 fn, a, abstr (a);,rerurn 0;,运行情况如下,Enter real number a please: -98.7654 ,abstr (-98.765400)=98.765400,下面是函数abstr被调用执行的情况:#include s,33,例3-6 求一元二次方程ax2+bx+c=0的根。,算法设计:一元二次方程式的根有下列情况:,当a=0,b=0时,方程无解;,当a=0,b0时,方程只有一个实根-c/b;,当a0时,方程的根为x=(-b(b,2,-4ac),1/2,)/(2*a)。其中, 当b,2,-4ac0时有两个实根;当b,2,-4ac0时,有两个虚根。,图3-8为上述算法的N-S图表示,它把上述逻辑关系表示得更为清晰。,b=0,输出“无解”,输出单根:,x=-c/b,假,真,disc0,输出两复数根,输出两实根,真,假,a=0,真,假,disc=b*b - 4*a*c,图3-12 求一元二次方程根的算法,例3-6 求一元二次方程ax2+bx+c=0的根。b=0输,34,include ,void solv_quadr_equa (float a, float b, float c),if (a=0.0),if (b=0.0),printf (no answer due to input errorn);,else,printf (the single root is %fn, -c/b);,else,double disc, twoa, term1, term2;,disc=b*b-4*a*c;,twoa=2*a;,term1=-b/twoa;,term2=sqrt (fabs (disc)/twoa;,if (disc0.0,printf (complex root:n real part=%f,imag part=%fn,term1, term2);,else,printf (real root:n root1=%f, root2=%fn,,term1+term2, term1-term2);,由此N-S图可以编写出以下的函数:,include 由此N-S图可以编写出以,35,3.3.3 if-else if结构,if-else if是一种多分支选择结构,用N-S图描述下右图所示,C语言中的格式如下左图所示:,if(表达式,1,),语句,1,else if(表达式,2,),语句,2,else if(表达式,n,),语句,n,else,语句,n+1,语句1,语句2,语句3,真,假,表达式1,假,真,表达式2,真,假,表达式3,3.3.3 if-else if结构if-else if是,36,例3-7 根据百分制分数决定成绩的等级:, 90分以上为A级;, 80分及以上,90分以下,B级;, 70分及以上,80分以下,C级;, 60分及以上,70分以下,D级;, 60分以下,E级。,下图为用if-else if结构描述的上述规则。,例3-7 根据百分制分数决定成绩的等级:,37,3.4,任务5:用switch语句实现菜单的选择执行,1. 问题描述,对显示的菜单,选择要执行的菜单序号,并显示要执行的菜单名。,2. 具体实现,P54程序,3. 知识分析,分支结构程序设计除if-else结构外,还包括switch结构。Switch结构是一种多路分支的选择结构程序设计。,3.4 任务5:用switch语句实现菜单的选择执行1. 问,38,switch是一种多分支选择结构,其形式如下图左所示,N-S结构图如下右图所示。,3.5 必备知识与理论,switch(表达式),case 常量表达式1:,语句序列1,case 常量表达式2:,语句序列2,case 常量表达式n:,语句序列n,default:,语句序列n+1,switch是一种多分支选择结构,其形式如下图左所示,N-S,39,这里,break语句的作用是中断该switch结构,即将流程转出switch结构。所以,,执行switch结构的就相当于只,执行与判断表达式相匹配的一个case子结构中的语句。,其实,可以将break看作为语句序列中必要的成分(位置在语句序列中的最后)。,switch(表达式),case 常量表达式1:,语句序列1,break;,case 常量表达式2:,语句序列2,break;,case 常量表达式n:,语句序列n,break;,default:,语句序列n+1,break;,这里,break语句的作用是中断该switch结构,即将流程,40,例3-11 根据百分制分数决定成绩的等级:,90分以上为A级;,80分及以上,90分以下,B级;,70分及以上,80分以下,C级;,60分及以上,70分以下,D级;,60分以下,D级。,例3-11 根据百分制分数决定成绩的等级:,41,/* 按成绩分等 */,#include ,int main(void),float score;,int grade;,printf(输入一个分数:);,scanf(%f,grade=score/10;,switch(grade),case 10:,case 9:printf(An);break;,case 8:printf(Bn);break;,case 7:printf(Cn);break;,case 6:printf(Dn);break;,case 5:,case 4:,case 3:,case 2:,case 1:,case 0:printf(En);break;,return 0;,/* 按成绩分等 */,42,3.6 必备知识与理论,条件运算符是C语言中唯一的三目运算符,即有三个参数参与运算。由条件运算符组成条件表达式的一般形式为:,表达式1 ? 表达式2 : 表达式3,其求值规则为:如果表达式1的值为真,则把表达式2的值作为该条件表达式的值,否则把表达式3的值作为该条件表达式的值。,条件运算符的优先级很低,仅仅比赋值操作符的级别高。其结合方式与赋值运算符一样是从右至左的。因此,表达式max=ab? ab相当于:,max=(ab?a:b);,3.6 扩展知识与理论,3.6 必备知识与理论 条件运算符是C语言中唯一的三目,43,3.7,任务6:用循环语句实现菜单的选择执行,1. 问题描述,对显示的菜单,选择要执行的菜单序号,并显示要执行的菜单名。,2. 具体实现,用for语句实现P60程序,用while语句实现P61程序,用dowhile语句实现P61-P62程序,3. 知识分析,循环结构程序设计包括while、do-while和for循环三种结构,对已知循环次数的循环多采用for循环;对循环次数不确定,循环首先执行一次的循环多采用do-while循环,而需要根据循环条件来确定循环是否要执行的,多采用while循环。,3.7 任务6:用循环语句实现菜单的选择执行1. 问题描述,44,3.8,必备知识与理论,3.8.1 while结构,while语句的一般形式为:,while(表达式) 语句,其中表达式是循环条件,语句为循环体。,while语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体语句;否则跳过循环体,而执行该结构后面的语句。在进入循环体后,每执行完一次循环体语句后,再对判断表达式进行一次计算和判断。当发现判断表达式的值为0时,便立即退出循环。,3.8 必备知识与理论3.8.1 while结构,45,例3-12 兔子繁殖问题。,著名意大利数学家Fibonacci曾提出一个有趣的问题:设有一对新生兔子,从第三个月开始它们每个月都生一对兔子。按此规律,并假设没有兔子死亡,一年后共有多少对兔子。,人们发现每月的兔子数组成如下数列:,1,1,2,3,5,8,13,21,34,,并把它称为Fibonacci数列。那么,这个数列如何导出呢?,观察一下Fibonacci数列可以发现这样一个规律:从第3个数开始,每一个数都是其前面两个相邻数之和。这是因为,在没有兔子死亡的情况下,每个月的兔子数由两部分组成:上一月的老兔子数,这一月刚生下的新兔子数。上一月的老兔子数即其前一个数。这一月刚生下的新兔子数恰好为上上月的兔子数。因为上一月的兔子中还有一部分到这个月还不能生小兔子,只有上上月已有的兔子才能每对生一对小兔子。,例3-12 兔子繁殖问题。,46,上述算法可以描述为,fib,1,=fib,2,=1 (1),fib,n,=fib,n-1,+fib,n-2,(n,=3) (2),式(1)为赋初值,式(2)为迭代公式。用C语言来描述式(2)为:,fib=fib1+fib2;,fib1=fib2; /* 为下一次迭代作准备*/,fib2= fib;,这里,fib1和fib2和不再仅代表第1个月和第2个月的兔子数,而作为中间变量,代表前两个月的兔子数,fib当前月的兔子数。下页图为Fibonacci算法的N-S图。表为迭代过程中fib1、fib2和fib的变化情形。,上述算法可以描述为fib=fib1+fib2;,47,图3.19 计算Fiboonacci数列的N-S图,当i=12,fib1=fib2,fib=fib1+fib2,初值:fib1=1,fib2=1,i=3,fib2=fib,输出fib,i+,图3-12 计算Fiboonacci数列的N-S图,迭代次数,3,4,5,6,7,8,9,10,11,12,fib,1,1,1,2,3,5,8,13,21,34,55,fib,2,1,2,3,5,8,13,21,34,55,79,fib,2,3,5,8,13,21,34,55,79,144,表 按照迭代算法变量fib1、fib2和fib3的变化情形,当i=12fib1=fib2fib=fib1+fib2初值,48,根据图3-12所示的算法。可以很容易地写出如下程序。,/* 计算Fibonacci数 */,#include ,int main(void),int fib1=1,fib2=1,fib,i=3;,while(i=12),fib=fib1+fib2;,fib1=fib2;,fib2=fib;,i+;,printf(“The Fibonacci number after 1 yer is:%dn”,fib);,return 0;,根据图3-12所示的算法。可以很容易地写出如下程序。/*,49,例3-13 百钱买百鸡问题。,公元前五世纪,我国古代数学家张丘建在算经一书中提出了“百鸡问题”:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、母、雏各几何?,(1) 基本解题思路,这是一个有名的不定方程问题:,cocks+hens+chicks=100 (1),5*cocks+3*hens+chicks/3=100 (2),式中:,cocks:鸡翁数,hens:鸡母数,chicks:鸡雏数,例3-13 百钱买百鸡问题。cocks+hens+chic,50,对上述不定方程问题,要先确定一个变量的值,才能对其进行求解。由问题中给出的条件,很容易得到三个变量的取值范围:,cocks: 019中的整数(因为每只鸡翁5钱,因此它不可能超过19只),hens: 033中的整数,chicks: 0100中的整数,基本的解题思路是:依次取cocks值域中的一个值,然后求其余两数,看是否合乎题意,合乎者为解。这个基本解题思路便是解本题的粗略算法,下面是它的伪代码描述,图3-13(1)为其N- S图。,s1: cocks=0; /*赋初值*/,s2: 当(cocks=19),s2.1: 找满足题意的hens, chicks;,s2.2: cocks+;,S3:输出一组cocks,hens和chichs,对上述不定方程问题,要先确定一个变量的值,才,51,图3-13(1) 百钱买百鸡的粗略算法,当(cocks=19),找满足题意的hens和chicks,输出一组cocks,hens和chichs,初始化:cocks=0,cocks +,图3-13(1) 百钱买百鸡的粗略算法 当(cocks=,52,(2) 对s2.1细化,思路1:把已确定的cocks代入式(1)与(2)中,求解方程,看能否找到满足题意的解。这种思路不太适合计算机求解。,思路2:在每个给定的cocks下,面对hens的取值范围内的各个值依次测试,看能找到哪些hens及chicks满足题意。于是得到如下s2.1细化算法。,用这段算法代替图3-13(1)中的“找满足题意的hens和chicks”,得到图3-13(2)所示的百钱买百鸡的N-S图算法。,s2.1.1: hens=0;,s2.1.2: 当(hens=33),s2.1.2.1: 找满足题意的chicks;,s2.1.2.2: hens+; /*即hens=hens+1*/,(2) 对s2.1细化 用,53,图3-13(2) 百钱买百鸡算法的细化算法,当(cocks=19),当(hens=33),初始化:cocks=0,输出一组cocks,hens和chichs,cocks +,hens=0,找满足题意的chicks,Hens+,图3-13(2) 百钱买百鸡算法的细化算法 当(cocks,54,(3) 对s2.1.2.1细化,对s2.1.2.1来说,cocks及hens都已确定,这时的chicks可以计算出:,chicks=100-cocks-hens,式(1)已满足。只要用式(2)指定的条件测试便可知这一组cocks, hens及chicks是否满足题意。满足则打印出一组解。于是s2.1.2.1可细化为:,图3.13(3)为进一步细化的百钱买百鸡算法。,s2.1.2.1:,chicks=100-cocks-hens;,if(5*cocks+3*hens+chicks/3.0)=100),printf (%d %d %dn, cocks, hens, chicks);,(3) 对s2.1.2.1细化图3.13(3)为进一步细化的,55,图3-13(3) 百钱买百鸡算法的细化算法,当(cocks=19),当(hens=33),cocks=0,cocks +,hens=0,chicks=100-cocks-hens,hens+,(5*cocks+3*hens+chicks/3.0)=100,输出一组,cocks,hens和chichs,(空),真,假,图3-13(3) 百钱买百鸡算法的细化算法 当(cocks,56,/* 百钱买百鸡问题 */,#include ,int main(void),int cocks=0;,printf(%8s%8s%8sn,cocks,hens,chicks);,while(cocks=19),int hens=0;,while(hens=E0),x=(x+a/x)*0.5;,return (x);,这里fabs是一个标准数学函数名。E0是误差要求,可以用define命令在程序头部作为一个符号常数进行定义,在不同情况下根据需要可以对它修改。,/* 计算平方根 */这,61,#include ,int main(void),double f=2.0;,printf( The root of %f is %fn,f,sq_root(f);,return 0;,用下面的主函数进行测试,测试结果如下:,The root of 2.000000 is 1.414216,#include 用下面的主函数进,62,3.8.3 for结构,为了说明for结构,先看下面一个程序段:,sum=0;,for (i=1;i=n;i+),sum=sum+i;,它是下面的控制结构的一个例子。,for (表达式1;表达式2;表达式3),循环体,为了说明for后面括弧中三个表达式的语句,将它改写为如下while结构:,sum=0;,i=1;/* 相当于for语句中的表达式1 */,while (i=n)/* 相当于for语句中的表达式2*/,sum=sum+i;/* for循环体*/,i+;/* 相当于for语句中的表达式3*/,3.8.3 for结构sum=0; 它是下面的控制结构的,63,显然,这三个表达式的作用是控制循环,故称循环控制表达式。表达式1称为初始化表达式;表达式2称为条件表达式;表达式3称为修正表达式。可以看出:for语句是将初始化、条件判断、循环变量值变化三者组织在一起的循环控制结构。for结构的格式可以表示为:,for语句的执行过程如下:,(1) 先执行表达式1(初始化表达式)。注意在整个循环中它只执行一次。,(2) 重复下面的过程:计算表达式2(判断表达式),若为真(非0),就执行一次循环体语句,然后再执行表达式3(修正表达式);再计算表达式2(判断表达式),判断是否为“真”,直至表达式2(判断表达式)的值为假(0),就不再执行循环体了。,for (初始化表达式;判断表达式;修正表达式),循环体语句,显然,这三个表达式的作用是控制循环,故称循环,64,在某些情况下,用for结构表示循环,显得紧凑而清晰。尤其是它能利用表达式3自动地使循环变量值发生改变,不像while结构那样要在循环体中设置“修正操作”。实际上,for语句中的表达式3并不仅限于修正循环变量,而可以是任何操作。例如前面介绍的求1+2+n的程序段可以改写为:,形成一个没有循环体的结构,或者说循环体是一个空语句(仅一个分号)。而表达式3成为一个逗号表达式,它包含两个简单表达式(包含了本应由循环体完成的功能),表达式的执行顺序从左到右。表达式1也是一个逗号表达式,它使sum和i都初始化。,for (sum=0,i=1; i=n; sum=sum+i,i+ );,在某些情况下,用for结构表示循环,显得紧凑,65,计算Fibonacci数程序,用for结构修改如下:,#include ,int main(void),int fib1=1,fib2=1,fib,i;,for (i=3;i=12;i+),fib=fib1+fib2;,fib1=fib2;,fib2=fib;,printf(“The Fibonacci number after 1 yer is:%dn”,fib);,return 0;,计算Fibonacci数程序,用for结构修改如下:,66,百钱买百鸡问题用for结构编写的程序如下:,#include ,int main(void),int cocks;,printf(%8s%8s%8sn,cocks,hens,chicks);,for(cocks=0;cocks=19; cocks+),int hens;,for(hens=0; hens=33; hens+),int chicks;,chicks=100-cocks-hens;,if(5*cocks+3*hens+chicks/3.0=100),printf(%8d%8d%8dn, cocks,hens,chicks);,return 0;,百钱买百鸡问题用for结构编写的程序如下:,67,例3-18 打印九九表。,下面用逐步求精的方法分析本例的解法。,表体共九行,所以首先考虑一个打印九行的算法s1:,下面进一步考虑如何“打印第i行”。因为每行都有九个数字,故“打印第i行”可以写为s1.1:,for(i=1; i=9;i+),打印第i行,打印换行符,for(j=1, j=9; j+),打印第j个数,例3-18 打印九九表。下面用逐步求精的方法分析本例的解法,68,“打印第j个数”即在第i行的第j列上打印一个数,大小为i*j,占4个字宽。故可写为,printf (%4d, i*j);,在写这个语句时,人们自然要考虑写不写换行符。显然不能在每个数字后面都换行,而只能在第9个数字后面写换行。实现只在第9个数字后面换行的办法是,打印完一行,即在j循环后写一个语句使换行:,printf (n);,于是,打印九九表的程序可写为:,“打印第j个数”即在第i行的第j列上打印一个数,大小为i*,69,/* 打印九九乘法表 */,#include ,int main(void),int i,j;,for (i=1;i=9; i+), /*实际上将9改为i,更符合数学上的习惯*/,for (j=1; j=9;j+),printf (“%d*%d=%4d,i,j,i*j);,printf (n);,return 0;,/* 打印九九乘法表 */,70,例3-19 用梯形法求数值积分。,定积分,的几何意义就是求曲线f(x)与直线y=0,x=a,x=b所围成的曲顶梯形的面积。当能找到f(x)的原函数F(x)时,利用牛顿-莱布尼兹公式:,可以精确地求出I值来。当f(x)的原函数不易找到时,便可以借助数值方法近似地求出I的值。,用数值方法计算定积分有两个关键:一是将连续的对象分割为容易求解的一些子对象;二是用迭代法对迭代表达式反复操作。下面介绍一种容易理解的方法梯形法。,由图3-16所示,一个曲顶梯形可以分割为许多小的宽为h的曲顶梯形。,例3-19 用梯形法求数值积分。,71,b,f(x),x,0,y,a,a+h,a+ih,a+ih+h,a+2h,图3-16 用梯形法求定积分,bf(x)x0yaa+ha+iha+ih+ha+2h图3,72,当h(h=(b-a)/n)很小时,每个小的曲顶梯形都可以近似看作是梯形,第i个小曲顶梯形的面积近似为:,s,i,=h/2f(a+ih)+f(a+(i+1)h),于是定积分的值(曲线所围成的面积):,当n时,就能准确地求出定积分S。在现实中,只要取相当大的n,使误差小于要求的值,就可以近似地计算出定积分S。,用迭代形式描述为:,for(i=1;i=n-1;i+),s=0.5*h*(f(a)+f(b),s=s+h*f(a+i*h),最后计算的结果,就是函数f(x)的定积分。,当h(h=(b-a)/n)很小时,每个小的曲顶梯形都可以近似,73,下面是一个利用梯形法求函数f(x)= 4-x的定积分的程序:,/* 用梯形法求积分 */,#include ,double f(double x);,int main(void),float a,b;,double s,h;,int n,i;,printf (输入计算的区间a,b);,scanf (%f, %f,printf (输入迭代的次数);,scanf (%d,h=(b-a)/n;,s=0.5*h*(f(a)+f(b);,for(i=1;i=n-1;i+),s+=f(a+i*h)*h;,printf(函数f(x)在区间%.2f,%.2f间的定积分值约为:%fn,a,b,s);,return 0;,#include ,double f(double x),return sqrt(4.0-x);,下面是一个利用梯形法求函数f(x)= 4-,74,循环结构的中途退出与重复周期的中途结束,下页图为循环结构中途退出(loop-and-half)与一个循环周期的中途结束的示意图。中途退出循环结构就是使用break语句,将流程转到该循环结构的后面。循环周期的的中途结束就是在重复执行到某一个循环周期的中间时,由于某种条件,不需要再执行循环体中后面的语句,提前结束该周期,而进入下一循环周期,在C语言中需要使用continue实现。这两种控制功能不仅用于while结构中,也可以用在dowhile和for重复结构中。,3.9 扩展知识与理论,循环结构的中途退出与重复周期的中途结束3.9 扩展知识与理论,75,while(),if(),break;,while(),if(),cotinue;,(a)循环结构中途退出,(b)一个循环周期的中途退出,while()while() (a)循环结构中途退出 (,76,3.9.1 中途退出循环结构break语句,break语句将流程转出switch结构。break语句还可以将流程中途转出任何一种循环结构。,例3-20 验证素数。,验证一个正整数n3的数是否为素数,一个最直观的方法是,看在2n/2中能否找到一个整数m能将n整除。若m存在,则n不是素数;若找不到m,则n为素数。这是一个穷举验证算法。这个循环结构用下列表达式控制:, 初值: m=2, 循环条件: m=n/2, 修正: m+,即这是一个for结构。它的作用是穷举2n/2中的各m值。循环体是判断n是否可以被m整除。显然,在这个过程中,一旦找到一个m可以整除n,则用该m后面的各数去验证已经没有意义了,需要退出循环结构。,3.9.1 中途退出循环结构break语句,77,按上述分析可以写出一个验证正整数n是否为素数的函数:,/* 验证素数 */,#include ,int main(void),int m,n,flag=1;,printf(请输入要测试的整数:);,scanf(%d,for (m=2;m=n/2;m+),if (n%m=0),flag =0; /* 设置非素数标志*/,break; /* 一旦找到一个m,断定该n非素数,不需再验证 */,flag?printf(%d是素数n,n):printf(%d不是素数n,n);,return 0;,按上述分析可以写出一个验证正整数n是否为素数的函数:/*,78,3.9.2 提前结束一个循环周期continue语句,例3-21 输出100200间的所有素数。,这个程序可以在例3.20的基础上进行。当测试到某个n存在一个因数m时,用break跳出内层循环复结构,同时在外层循环结构中要跳过输出语句,进入对下一个数的测试。,按上述分析可以写出一个验证正整数n是否为素数的函数:,3.9.2 提前结束一个循环周期continue语句,79,/* 输出素数 */,#include ,int main(void),int m,n,flag;,printf(nThe primers from 100 to 200 is:n);,for(n = 101; n = 200; n +=2) /* 仅测试100200间的奇数 */,flag = 1; /* 设置标志 */,for(m = 2; m = n/2; m +),if(n % m = 0),flag = 0; /* 改变标志 */,break; /* 跳出内层循环结构 */,if(flag = 0) /* 判断标志 */,continue; /* 跳出过输出语句进入下一周期 */,printf(“%d,”,n);,printf(n);,return 0;,/* 输出素数 */,80
展开阅读全文