基本程序设计技术课件.ppt
《基本程序设计技术课件.ppt》由会员分享,可在线阅读,更多相关《基本程序设计技术课件.ppt(109页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、关于基本程序设计技术现在学习的是第1页,共109页第四章第四章基本程序设计技术基本程序设计技术现在学习的是第2页,共109页学习程序设计需要注意规律性的东西。三种流程模式是重要总结。本章还讨论:基本输入和输出 递归的程序设计 其他控制结构 顺序模式最简单 选择模式:要确定判断条件及不同情况下的动作 开始的难点在实现重复执行的循环。重复执行比较复杂,牵涉问题多,是本章重点现在学习的是第3页,共109页4.1循环程序设计写循环首先要发现循环。注意计算中的重复性动作,引进循环可能统一描述和处理。重复动作的常见实例:一批类似数据做同样加工处理 累积一批可按规律算出的数据(累加等)反复从一个结果算出下一
2、结果(递推)若重复次数很多,就应该考虑用循环 如果重复次数无法确定,就必须用循环描述现在学习的是第4页,共109页例:求13到315所有数的平方根之和。可以一个个地加,但更方便的方法是写循环。需要一个变量保存部分和,逐步把各平方根加上去;需要一个变量保存变动轨迹,从初值开始每次修改。典型for循环。假定已有总和变量sum和循环变量n:for(sum=0.0,n=13;n=13;-n)sum+=sqrt(n);这里的两个循环等效。一般采用向上循环现在学习的是第5页,共109页可以用while语句重写,两种结构功能上等效。例,求 13,315 间每隔7的各整数的平方根之和。一般不用浮点数控制循环,
3、尤其是增量为小数或包含小数时。例:求从0到100每隔0.2的数的平方根之和:double sum,x;for(sum=0.0,x=0.2;x=100.0;x+=0.2)sum+=sqrt(x);由于浮点计算误差,不能保证循环500次。应写:int n;double sum;for(sum=0.0,n=1;n=500;+n)sum+=sqrt(0.2*n);现在学习的是第6页,共109页例1:打印出 1 到 200 间的完全平方数。方法一:逐个检查,遇平方数打印。重复做,每次检查一个数。循环框架:for(n=1;n=200;n+)if(n 是完全平方数)打印 n;需填充:数是否完全平方数,没有直
4、接判断手段。可以顺序检查,是否存在某数,其平方恰为n。这构成(循环内的)新循环,需要一个新循环变量。m可以从1开始,递增,直至m*m大于n:for(m=1;m*m=n;m+)if(m*m=n)打印 n;现在学习的是第7页,共109页综合起来可得到完整程序:#include int main()int m,n;for(n=1;n=200;n+)for(m=1;m*m=n;m+)if(m*m=n)printf(%d,n);printf(n);/*最后输出一个换行符*/return 0;内层循环结束:1,找到m使m*m=n(n是完全平方数)2,试探了所有可能,但都不成功(n不是)现在学习的是第8页,
5、共109页方法二:需要打印的一定是从1开始连续几个整数的平方,可从1开始打印到平方大于200为止。for(n=1;n*n=200;+n)printf(%d,n*n);/*注意打印什么*/还可以考虑利用递推公式:12111nnn方法一:产生所有备选数据(1到200的整数),检查排除不合格的。生成与检查是解决问题的常用方法。方法二是针对具体问题的特定方法。现在学习的是第9页,共109页例 2:写函数判断整数是否为素数(谓词)。类型特征可用 int isprime(int),返回0/1值n是素数则它没有真因子,m是n的因子用(n%m=0)描述,若 mn 就够了。函数定义:int isprime(in
6、t n)/*n是否素数*/int m=2;for(;m*m=n;m+)if(n%m=0)return 0;return 1;/*没有因子,是素数*/现在学习的是第10页,共109页从循环中退出:isprime发现一个因子就可做结论。return使函数结束,也导致循环结束。函数不完善,对1给出“是素数”,负数也会给出不合理结果。应该在循环前处理特殊情况:if(n=1)return 0;负数问题?如果需要可以另外考虑处理。现在学习的是第11页,共109页例3,艰难旅程(浮点误差)。乌龟要去环球。第1秒爬1米,第2秒爬1/2米,第3秒爬1/3米,第4秒爬1/4米,。问一小时能爬出多远?爬20米需多少
7、秒?根据数学,乌龟能完成环球,可以爬得任意远。这里想比较float和double的计算误差情况。这里只考虑20米需要多少时间。写出下面函数:long scndsf(float d)long i;float x=0.0;for(i=1;x d;+i)x+=1/(float)i;return i-1;现在学习的是第12页,共109页写下面语句,执行时总也不输出:printf(%lds,%fmn,scndsf(20.),20.);修改为如下语句:for(x=10.0;x=1E-6)x1=x2;x2=(2.0*x1+x/(x1*x1)/3.0;return x2;这个程序的一个缺点是同一表达式写了两次
8、。书上利用C的特点给了一种简化写法,供参考 学习了其他结构后有改进的写法现在学习的是第17页,共109页例5:定义函数,利用公式求 近似值。设为double dsin(double x)。方法:循环累加,n 趋向无穷的过程中项值趋于0,而累加值趋向函数值。需要用循环。保存累加和的变量sum,循环中求出的项值用 t 保存。sin()()!xxnnnn121210sinxsum=0.0;对n为0计算t;while(需要继续)sum=sum+t;计算下一个t;循环结束条件:例如用项绝对值小于 。106现在学习的是第18页,共109页问题:t 的值如何计算?第一个 t就是 x;分析可以发现项值的递推公
9、式:ttxnnnn 12221/()double dsin(double x)double s=0.0,t=x;int n=0;while(t=1E-6|t=-1E-6)s+=t;n=n+1;t=-t*x*x/(2*n)/(2*n+1);return s;现在学习的是第19页,共109页一些情况:实参值很小时,循环将很快结束。实参绝对值很大时循环可能做许多次,项的绝对值可能达到很大,n 值也可能超出整数的表示范围 可考虑用fmod把参数归约到0,2 之内启示:理解问题非常重要。发现了项的递推性质能节省许多计算(否则就要再写一个嵌套循环完成项的计算)级数收敛性质能帮人认识情况,改进计算方法写程序
10、时必须仔细考虑问题本身的性质现在学习的是第20页,共109页4.2 循环中的问题从循环中退出有时需要从正在执行的循环中退出。对6200的各偶数验证哥德巴赫猜想,利用isprime:for(n=6;n=200;n+=2)for(m=3;m=n/2;m+=2)if(isprime(m)&isprime(n-m)printf(%d=%d+%dn,n,m,n-m);问题:有多种分解时将产生多对输出。如对10:10=3+7 10=5+5前面写isprime时借助return退出了循环现在学习的是第21页,共109页希望每个偶数只输出一行。怎样在发现素数对后停止?增加对循环的控制:把发现素数分解作为条件加
11、入。引入整型变量found,值0表示未发现素数对。发现时将found赋1。内循环开始时found置0。应修改内层循环条件。修改后循环是:for(n=6;n=200;n+=2)for(found=0,m=3;m=n/2&!found;m+=2)if(isprime(m)&isprime(n-m)printf(%d=%d+%dn,n,m,n-m);found=1;这种需求很常见。C语言引进了专门的控制语句现在学习的是第22页,共109页break语句,形式:break;break只能用在循环语句(及switch语句)里,使最内层(循环可嵌套)循环语句(或switch)立即停止,执行从被终止循环(或
12、switch)之后继续。可用break解决循环中退出问题,放在条件下。完成前例的程序段:for(n=6;n=200;n+=2)for(m=3;m=n/2;m+=2)if(isPrime(m)&isPrime(n-m)printf(%d=%d+%dn,n,m,n-m);break;现在学习的是第23页,共109页利用break重写前面求立方根的函数:double cbrt(double x)double x1,x2=x;if(x=0.0)return 0.0;while(1)x1=x2;x2=(2.0*x1+x/(x1*x1)/3.0;if(fabs(x2-x1)/x1)1E-6)break;r
13、eturn x2;也可以在 break 处直接写 return x2。现在学习的是第24页,共109页循环中的几种变量循环中常出现几类变量,注意这些有助于对循环的思考和分析。也是写循环程序的经验总结注意:分类不是绝对的,不同类别没有截然界限1)循环控制变量(循环变量):循环前设初值,循环中递增/递减,达到/超过界限时循环结束。它们控制循环的进行/结束。for中常有这类变量。for(n=0;n=0;-n).for(n=2;n 52;n+=4).这种循环是固定次数的循环。这种循环可能展开现在学习的是第25页,共109页2)累积变量:循环中常用+=或*=等更新。初值常用运算的单位元(加用0;乘用1为
14、初值)。循环结束时变量终值被作为循环计算结果。3)递推变量:前两类变量的推广。几个协同工作的变量,每次由几个变量推出一个新值,其余依次更新。对变量x1、x2、x3,循环体可能有序列:x1=x2;x2=x3;x3=.x1.x2.;例如上面cbrt里的变量x1和x2。现在学习的是第26页,共109页写循环时要考虑和解决问题列表:循环涉及到哪些变量,需引进哪些临时性变量?循环如何开始?循环开始前给变量什么初值?循环中变量的值如何改变?什么情况下继续(或终止)循环?循环终止后如何得到所需结果?用哪种结构实现循环,等等。工作方式:分析问题,发掘线索,最终完成程序。程序设计不是教条,典型问题也无标准答案。
15、并非最简单的问题总有多种解决方法,往往各有长短。“正确”程序常有优劣之分。现在学习的是第27页,共109页4.3循环与递归程序中有循环可能导致很长的计算。没有循环结构也能描述这类计算。C语言允许递归,可在函数内调用自身,程序常常更简单清晰。例:定义计算整数阶乘的函数:12(n-1)n乘的次数依赖于n,定义时不知道,每次用可能不同。程序的典型情况:计算“次数”依赖某些参数的值。省略号不科学。严格定义需用递归形式。现在学习的是第28页,共109页nnnnn!()!1010注意递归定义的形式。这也提出了一种计算方法。如果语言允许递归定义函数,就可以直接翻译为程序。C允许递归定义:在函数定义内调用被定
16、义函数本身。类型特征可定为:int fact(int)阶乘值增长极快(数学),更合适的类型特征:long fact(long)现在学习的是第29页,共109页递归的函数定义:long fact(long n)return n=0?1:n*fact(n-1);也可以用循环定义:long fact1(long n)long i,f=1;for(i=2;i=n;+i)f*=i;return f;比递归定义长,需要引进多个局部变量。现在学习的是第30页,共109页fact(3)3*fact(2)fact(2)2*fact(1)fact(1)1*fact(0)fact(0)调用 fact(3)返回值 1
17、返回值 1返回值 2返回值 6图 3.3fact(3)的计算过程fact实现的计算过程很不简单。计算中fact被递归调用的次数由实参确定。考虑负参数值处理。可改为:n=1?1:.现在学习的是第31页,共109页递归定义导致的计算过程参数不同fact递归调用次数(步数)不同。定义只有一个语句,可能要许多步才能完成。包含递归(和循环)的程序产生的计算过程和性质更复杂,能完成更复杂工作,理解和书写也更困难。递归的函数定义需要条件表达式或if,必须区分:直接给出结果的情况。是递归的基础 需要递归处理的情况。其中把对较复杂情况的计算归结为对更简单情况的计算基本运算/关系判断/条件表达式,加函数定义和递归
18、定义构成了一个(理论上)“足够强的”的程序语言。现在学习的是第32页,共109页程序实例Fibonacci(斐波那契)序列的递归定义:FFFFFnnnn0112111,()Fibonacci 序列增长很快,返回值选long。递归定义:long fib(int n)return n2?1:fib(n-1)+fib(n-2);负参数值定义为 1。这是“合理”处置。问题分析:这个程序好不好?一方面,很好!程序与数学定义的关系很清晰,正确性容易确认,定义易读易理解。现在学习的是第33页,共109页但这个定义有一个本质性缺点。示意图:fib(5)fib(4)fib(3)fib(3)fib(2)fib(2
19、)fib(1)Fib(2)fib(1)fib(1)fib(0)fib(1)fib(0)fib(1)fib(0)图4.1 fib(5)计 算 中 的 函 数 调 用 情 况现在学习的是第34页,共109页存在大量重复计算,参数越大重复计算越多。有关系吗?随着参数增大,计算中重复增长迅速,最快的微机上一分钟大约可以算出fib(45)参数加1,fib多用近一倍时间(指数增长)。最快的微机一小时算不出fib(55),算fib(100)要数万年计算需时间,复杂计算需要很长时间。这是计算机的本质特征/弱点。说明它不万能,有些事清“不能”做。求Fibonacci 值有更好计算办法(下面介绍)。现在学习的是第
20、35页,共109页人们发现了许多实际问题,理论上说可用计算机解决(可写出计算它的程序),但对规模大的情况(“大的参数 n”),人类永远等不到计算完成。这时能说问题解决了吗?理解这个情况对于理解计算机是非常重要的。这里有一大类问题称为计算中的“难解问题”,其中有许多很实际的问题(规划、调度、优化等)。这方面的理论和实际技术的研究极为重要:计算复杂性,难解问题,“P=NP?”问题。另外,对于许多问题的实用的有效算法,有极大的理论价值和实际价值。现在学习的是第36页,共109页为计算过程计时统计程序/程序片段的计算时间有助于理解程序性质。许多语言或系统都提供了内部计时功能。有关函数在time.h,统
21、计程序时间时程序头部应写:#include 在程序里计时,通常写表达式:clock()/CLOCKS_PER_SEC得到从程序开始到表达式求值时所经历的秒数。注意:有些老的C系统(如Turbe-C)用 CLK_TCK。现在学习的是第37页,共109页确定计算fib(45)所需要的时间的程序:#include#include long fib(int n)return n=1?1:fib(n-1)+fib(n-2);int main()/*自己做其他试验*/double x;x=clock()/CLK_TCK;fib(45);x=clock()/CLK_TCK-x;printf(Timing f
22、ib(45):%f.n,x);return 0;现在学习的是第38页,共109页Fibonacci数的递推计算 易见 1)F1和F2是12)知道连续两个Fibonacci数,就可算出下一个递推计算方式:逐个前推,可用循环实现:long fib1(int n)long a=1,b=1,c,i;if(n=1)return 1;for(c=a+b,i=2;i n;+i)a=b;b=c;c=a+b;return c;/*对吗?*/现在学习的是第39页,共109页循环结束时i等于n,这时c的值是Fn。要得到此结论,可设法证明:每次判断 i 的值时c正是 Fi。上面循环保证这种关系,可以通过归纳证明:fo
23、r(c=a+b,i=2;i n;+i)a=b;b=c;c=a+b;第一次判断时 i 的值是 2,c 的值2,正是 Fi(且 a 的值是Fi-1,b 的值是Fi-2)若某次判断时 i 值是 k(小于n),循环体中的语句使a变成Fk-1,b变成Fk,c变成Fk+1。i 值增 1 使我们又有a为Fi-2,b变成Fi-1,c变成Fi 根据归纳法,每次判断 i 的值时c正是 Fi。现在学习的是第40页,共109页 循环实现重复性计算,循环体可能执行多次。如何保证对各种数据都能正确完成计算?循环中变量不断变化。写循环要考虑变量间的关系,保证某些关系在循环中不变:循环的不变关系。写循环时最重要的就是想清循环
24、中应维持变量间的什么关系才能保证循环结束时变量能处在所需状态。写完循环后应仔细检查是否满足要求。循环不变关系(循环不变量)是理解循环、写好循环的关键。这个方面有很多研究,有许多理论结果。现在学习的是第41页,共109页问题:用循环的函数比用递归定义的好吗?新函数在计算时间上有极大优越性。计算时间由循环次数确定。循环体执行次数大致为n。fib(100)只需约100次循环,几乎察觉不到所花费时间。新函数定义较复杂,有复杂的循环。要理解程序意义,确认函数对任何参数都算出Fibonacci值,需要借助“循环不变关系”的概念和细致分析。上面分析中没考虑数据表示范围,long类型一般无法表示fib(100
25、)。注意:这个例子并不是说明递归比循环的效率低。完全可以写出计算fib的同样高效的递归定义的函数现在学习的是第42页,共109页求最大公约数(greatest common divisor,GCD):写函数 long gcd(long,long)方式1:k取初值1后递增,大于m或n之一时结束。如何得到所需结果?m和n可能有多个公约数,最后的k值不是m和n的公约数(它已大于两数之一)。解法1:逐个检查,直到找到能同时整除m和n的最大整数(生成与检查)。需辅助变量k记录检查值。简单方式:k顺序取值(初值/更新/结束),可用循环实现。需要记录循环中找到的公约数。现在学习的是第43页,共109页只需记
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基本 程序设计 技术 课件
限制150内