《Pascal语言程序设计及算法基础(肖教宁)》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库。
注:本教程授课时间为十八课时,学生上机练习时间为十八课间,共计三十六课时。可同时对六十名学生授课。第一章简单程序2第一节Pasca!程序结构和基本语句2第二节顺序结构程序与基本数据类型7第二章分支程序10第一节条件语句与复合语句10第二节情况语句与算术标准函数12第三章循环程序16第一节for循环16第二节repeat循环23第三节While循环27第四章函数与过程33第一节函数33第二节自定义过程36第五章Pascal的自定义数据类型41第一节数组与子界类型41第二节二维数组与枚举类型49第三节集合类型58第四节记录类型和文件类型63第五节指针类型与动态数据结构70第六章程序设计与基本算法75第一节递推与递归算法75第二节回溯算法82
1第一章简单程序无论做任何事情,都要有一定的方式方法与处理步骤。计算机程序设计比日常生活中的事务处理更具有严谨性、规范性、可行性。为了使计算机有效地解决某些问题,须将处理步骤编排好,用计算机语言组成“序列”,让计算机自动识别并执行这个用计算机语言组成的“序列”,完成预定的任务。将处理问题的步骤编排好,用计算机语言组成序列,也就是常说的编写程序。在Pascal语言中,执行每条语句都是由计算机完成相应的操作。编写Pascal程序,是利用Pascal语句的功能来实现和达到预定的处理要求。“千里之行,始于足下”,我们从简单程序学起,逐步了解和掌握怎样编写程序。第一节Pascal程序结构和基本语句在未系统学习Pasca!语言之前,暂且绕过那些繁琐的语法规则细节,通过下面的简单例题,可以速成掌握Pascal程序的基本组成和基本语句的用法,让初学者直接模仿学习编简单程序。[例1.1]编程在屏幕上显示“HelloWorld!”。Pasca!程序:Programexll;BeginWritelM'HelloWorkl!');ReadLn;End.这个简单样例程序,希望大家的程序设计学习能有一个良好的开端。程序中的Writein是ー个输出语句,它能命令计算机在屏幕上输出相应的内容,而紧跟Writein语句后是ー对圆括号,其中用单引号引起的部分将被原原本本地显示出来。[例1.2]已知一辆自行车的售价是300元,请编程计算a辆自行车的总价是多少?解:若总售价用m来表示,则这个问题可分为以下儿步处理:①从键盘输入自行车的数目a;②用公式m=300*a计算总售价;③输出计算结果。Pasca!程序:ProgramEx12;Vara5m:integer;BeginWrite(ta=,);ReadLn(a);M:=300*a;{程序首部}{说明部分}(语句部分){输入自行车数目}{计算总售价}
2Writeln('M=\m);{输出总售价}ReadLn;{等待输入回车键}End.此题程序结构完整,从中可看出ー个Pasca!程序由三部分组成:(1)程序首部由保留字Program开头,后面跟ー个程序名(如:Exll);其格式为:Program程序名;_程序名由用户自己取,它的第一个字符必须是英文字母,其后的字符只能是字母或数字和下划线组成,程序名中不能出现运算符、标点符和空格。(2)说明部分程序中所用的常量、变量,或类型、及过程与自定义函数,需在使用之前预先说明,定义数据的属性(类型)。[例1.2]程序中VarS,R,C:Real,是变量说明,此处说明S,R,C三个变量均为实数类型变量。只有被说明为某ー类型的变量,在程序中才能将与该变量同类型的数值赋给该变量。变量说明的格式为:Var变量表:类型;(3)语句部分指由保留字Begin(开始)至End.(结尾)之间的语句系列,是解决问题的具体处理步骤,也是程序的执行部分。Pascal程序不管是哪部分,每句末尾都必须有分号(;),但允许最接近End的那个语句末尾的分号省略:程序结束的End末尾必须有圆点(.),是整个程序的结束标志。程序中花括号“{ド之间的部分为注释部分。Pascal程序结构可归纳用如下的示意图来表示:Program程ノ予名:标号说明:(Label)常量说明:(Const)类型说明:(Type)变量说明:(Var)过程或函数说明:Begin语句系列:End.图1.1Pascal程序的结构说明部分程序体(主程序)语句部分程序首部把处理问题的步骤编成能从上到下顺序执行的程序,是简单程序的基本特征。再来分析下面两道例题的Pasca!程序结构和继续学习基本语句。[例1.3]编程计算半径为R的圆的面积和周长。解:这是ー个简单问题,按数学方法可分以下几步进行处理:①从键盘输入半径的值R:{要求告诉圆的半径R}
3②用公式S=nR2计算圆面积;计算圆周长;Pasca!程序:ProgramExl3;VarR,S»C:Real;{程序首部}BeginWrite('R二?');Readln(R);S:=Pi*R*R;C:=2*Pi*R;WritelnCS=',S);WritelnCC士,C);Readln{说明部分}{语句部分}{输入半径)(圆面积公式S=nR2}{圆周长公式C=2"R){输出结果}(等待输入回车键}③用公式C=2nR④输出计算结果。End.程序中Pi是Pascal提供的标准函数,它返回圆周率的近似值:3.1415926…。(:=)是赋值符号,赋值语句的格式为:变量:=表达式:赋值语句的作用是将:=右边表达式的值记录到左边的变量中。Writein是输出语句,输出语句有三种格式:①Write(输出项1,输出项2);{执行输出后光标不换行}②Writein(输出项!,输出项2);{执行输出后光标换到下一行}③WriteinI{仅输出空白且光标换到下一行}Writein语句后面的圆括号以内部分均为输出项,可以是多项,各项间用逗号分隔;对单引号里的内容按照引号内的原样(字符)输出显示。如果输出项是表达式,则只输出表达式的值,而不是表达式本身。[例1.4]输出两个自然数相除的商和余数。解:设被除数、除数、商和余数,分别为A,B,C,D,均为变量,且都是整数类型。题中未给出具体的自然数A、B,可采用键盘输入方式。①给出提示,从键盘输入a,b;②显示两数相除的数学形式;③求出a除以b的商c;④求出a除以b的余数d;⑤紧接等式后面输出显示商和余数。Pasca!程序:ProgramExl4:Vara,b,c,d:integer;BeginWrite(lNPUTA,B:');{给出提示信息}
4Readln(a,Writein;Write(a,ソ‘,b,'=')c:=adivb;d:=amodb:Writeln(C,d);Readln{输入a,b){输出一空行}{输出等式之后不换行}{整除运算,取商的整数部分}{相除求余运算,取商的余数部分}{输出后自动换行){等待输入回车键}End.执行本程序中第一个Write语句,输出其引号以内的ー串提示信息,是给紧接着的输入语句提供明确的提示(要求),有“一目了然,人机对话”之效果。Readln是一个特殊的输入语句,要求输入一个回车(换行)才能往下执行。Readln是输入语句,它的・般格式为:①Read(变量1,变量2);②Readln(变量1,变量2);③Readln前两种格式均要从键盘给变量输入数据,输入时,所键入的数据之间以空格为分隔,以回车为输入结束。若多输入了数据(即数据个数超过变量个数),Read语句读完数据之后,能让后续的读语句接着读取多下来的数据;而Readln语句对本行多输入的数据不能让后续语句接着读取多下来的数据。为了防止多输入的数据影响下ー个输入语句读取数据,建议尽量使用Readln语句输入数据。第三种格式不需输入数据,只需按入一个回车键。[例1.5]自然数的立方可以表示为两个整数的平方之差,比如43=1〇2一62,请输出自然数1996的这种表示形式。(这里的ペ用臼乘二次的形式4*4*4表示;IOユ也用自乘二次的形式1〇・1〇表示)解:此题没有现成的计算公式能直接利用,但可以自行推出处理方法或构建适当的运算公式,按着构想的处理方案编排出各步骤。设这个自然数为N,两个平方数分别为X,Y,将问题表示为求N3=X2-Y2①先找出X的值,仔细观察题中的示例,用数学方法归纳可得出X=N*(N+l)/2;(构成本题可用的计算公式)②再仔细观察,发现丫值比X小一个N值,即Y=X—N;③输出等式N3=X2—Y2或N*N*N=X*X—Y*丫Pasca!程序:ProgramEx15;ConstN=1996;{常量说明}VarX,Y:Longint;{变量说明,此题计算中的数值较大,用长整型}BeginX:=N*(N+l)div2;{div是整除运算}Y:=X-N;Writeln(N,'*',N,'*',N;=',X;*',X;—',Y,'*',Y);{输出结果)
5End.本程序中N是常量,X,Y是变量,为长整数类型(Longint);程序中的div是整除运算,其结果只取商的整数部分:[例1.6]求一元二次方程x2+3x+2=0的两个实数根。解:方程的系数是常量,分别用a,b,c表示,可运用数学上现成的求根公式求方程的根,采取如下方法:①先求出d=b2>4ac;(求根公式中需用开方运算的那部分)②再用求根公式算出xl,x2的值。(xl,x2=?)③输出xl,x2.Pasca!程序:programExl6;Consta=1;b=3;c=2;Vard:integer;XI,X2:Real;Begind:=b*b-4*a*c;xl:=(-b+sqrt(d))/(2*a);x2:=(-b-sqrt(d))/(2*a);WritelnCXl=',XI,1f:6,Readln'X2=',{常量说明}{a,b,c表示方程系数){d为整型变量){XI,X2为实型变量){求方程的根}X2);{输出结果}{等待输入ー个回车键}2.3.4.求右图所示边长为5.6的正立方体表面积。已知图园柱体的高为12,底面园的半径为7,End.本程序中的a,b,c均为常量;变量d是整数类型,而变量xl,x2则是实数类型,因为运算式中的Sqn(d)开平方运算和(7)除法运算使结果为实数。Sqrt()是开平方函数,是Pascal系统的ー个标准函数。习题1.1模仿例题编程1.加法计算器:编程由键盘输入两个整数a和b,计算出它们的和并输出到屏幕上。某梯形的上底、下底和高分别为8,12,9,求该梯形的面积。(梯形面积公式为S=(上底+下底)x髙5.计算某次考试语文、数学、英语和计算机等四科的总成绩与平均成绩。(请用输入语句从键盘输入各科成绩分)
6第二节顺序结构程序与基本数据类型前面的简单程序已体现出处理问题步骤、思路的顺序关系,这就是顺序结构程序。[例1.7]交换两个变量的值:由健盘输入两个正整数A和B,编程交换这两个变量的值。解:交换两个变量的值,可以想象成交换两盒录音带(称为A和B)的内容,可以按以下步骤处理:步骤①:拿一盒空白录音带C为过渡,先将A翻录至C;步骤②:再将B翻录至A;步骤③:最后将C翻录至B。这样操作,可达到题目要求。Pasca!程序:ProgramExaml7;Vara,b,c:integer;BeginWrite(tA,B=,);Readln(a,b);C:=A;{等价于步骤1}A:=B;{等价于步骤2}B:=C;{等价于步骤3)Writeln(A,B);End.[例1.8]分钱游戏。甲、乙、丙三人共有24元钱,先由甲分钱给乙、丙两人,所分给的数与各人已有数相同;接着由乙分给甲、丙,分法同前:再由丙分钱给甲、乙,分法亦同前。经上述三次分钱之后,每个人的钱数恰好一样多。求原先各人的钱数分别是多少?解:设甲、乙、丙三人的钱数分别为A,B,C。用倒推(逆序)算法,从最后结果入手,按反相顺序,分步骤推算出每次各人当时的钱数:(在每个步骤中,各人钱数分别存在A、B、C中)步骤①:A=8B=8C=8{这是最后结果的钱数,三人都一样多}步骤②:A=A/2(=4)B=B/2(=4)C=A+B+C(=16){A,B未得到丙分给的钱时,只有结果数的一半;C应包含给A,B及本身数三者之和}步骤③:A=A/2(=2)C=C/2(=8)B=A+B+C(=14){A,C未得到乙分给的钱时,只有巳有数的一半;B应包含给A,C及本身数三者之和}步骤④:B=B/2(=7)C=C/2(=4)A=A+B+C(=13)C未得到甲分给的钱时,只有巳有数的一半;A应包含给B,C及本身数三者之和}步骤⑤:输出A(=13)B(=7)C(=4){此时的A,B,C就是三人原先的钱数}Pasca!程序:ProgramExaml8;Vara,b,c:integer;Begina:=8;b:=8;c:=8;{对应于步骤①)a:=adiv2;b:=bdiv2;c:=a+b+c;{对应于步骤②}
7a:=adiv2;c:=cdiv2;b:=a+b+c;{对应于步骤③}b:=bdiv2;c:=cdiv2;a:=a+b+c;{对应于步骤④}Writeln('a±,a,'4,'b=',b,'4,'c=',c);{输出)ReadlnEnd.细心观察,会发现本程序语句的顺序很关键。此例用反推顺序(逆序),按步骤正确推算出各变量的值。当然,有的问题可按正序步骤编程,这类程序都称为顺序程序。本程序Writein语句的输出项含有('4),这里的冒号用来指定该项显示所占宽度,此处是输出4个空格即(空格项占4格)。[例1.9]有鸡兔同笼,头30,脚90,究竟笼中的鸡和兔各有多少只?解:设鸡为J只,兔为T只,头为H,脚为F,贝リ:J+T=30①2*J+4*T=90②解此题暂不必采用数学上直接解方程的办法,可采用“假设条件与逻辑推理”的办法:假设笼中30个头全都是兔,那么都按每头4只脚计算,总脚数为(4*H),与实际脚数(F)之差为(4*H—F),如果这个差=0,则笼中全是兔(即鸡为0只);如果这个差值>0,说明多计算了脚数,凡是鸡都多给算了两只脚,用它除以2就能得到鸡的只数,处理步骤为:①J=(4*H—F)/2{先用脚数差值除以2算出鸡的只数)②T=H-J{再用总头数减鸡数算出免的只数}按此方法,这两步运算必须注意先后顺序オ会符合运算逻辑。Pasca!程序:ProgramExaml6;ConstH=30;{常量说明}F=90;VarJ,T:byte:{为字节类型的整数}BeginJ:=(4*H-F)div2;{整除运算}T:=H-JWritein(7=',J,'6,T=',T);ReadlnEnd.本程序中H,F为常量,变量J,T为byte类型,属于整数类型。Pascal定义了五个标准整数类型,如下表所示:类型取值范围占字节数格式Shortint(短整型)-128..1271带符号8位Integer(整型)-32768.327672带符号16位
8Longint(长整型)-2147483648..21474836474带符号32位Byte(字节型)0..2551无符号8位Word(字型)0..655352无符号16位在前面程序中常用的数据类型除整数类型,还有实数类型。Pasca!还定义了五个标准实数类型,列表所示如下:类型取值范围占字节数有效数字Real2.9X10-39~1.7X103867~8位Single1.5X1O-45~3.4X1038411~12位DoubleS.OXIO-^-I.VXIO308815~16位Extended1.9X1O495I~1.1X1049321019~20位Comp-263+l~238-l819-20位在TurboPasca!中实数的表示用科学记数法,可认为由三部分组成:#.##E+##或#.##E-##①#.##表示有效数字;②E表示以10为底的‘幕;③钙#或"##是指数部分,+号可省略。例如:1.7E+38可写成1.7E38(等同于1.7X1038)。在实数类型定义下,即使是整数,在程序执行时系统也将自动转换成科学记数形式,试请运行下面程序并注意观察运行结果:ProgramExam17;{X为实数类型}{把整数180赋给实数类型变量X}{输出的x自动表示成实数形式}Varx:real;BeginX:=180;Writein('x=\x);ReadlnEnd.习题1.21.已知△ABC中的三边长分别为25.76,74.03,59.31I求△ABC的面积。〇其中P=(计算公式:S=2.某车棚存有自行车和三轮车共65辆,它们的轮子数合计为150个。求该棚内存有的自行车和三轮车各是多少辆?3.甲、乙、丙三人分别有磁带36,48,64盒。先由甲把自己的磁带平均分为三份,分给乙、丙各ー份,自己留下ー份;接着是乙,最后是丙,都按甲的方法处理。编程输出甲、乙、丙在上述过程中各人的磁带数分别是多少?(输出所有的中间结果)4.五位好朋友相聚。第一位朋友带来了很多糖块赠送给各位朋友,使每人的糖块在各自原有的基础上翻了一倍;接着第二位好友也同样向每人赠送糖块,他同样使每人的糖块在各人已有的数量上翻了一倍;第三、第四、第五位好友都照此办理。经过这样的赠送之后,每人的糖块恰好都为32块。问各位好友原先的糖块数分别是多少?
9第二章分支程序在程序设计中,许多问题是在一定条件下オ选择某种处理方式的,这就需要用条件判断语句或情况选择语句进行处理。程序执行中将出现选择(分支),根据条件只选择执行部分语句,不一定都是按原顺序从头到尾地执行所有语句,这样的程序称为分支程序。第一节条件语句与复合语句[例2.1]某服装公司为了推销产品,采取这样的批发销售方案:凡订购超过100套的,每套定价为50元,否则每套价格为80元。编程由键盘输入订购套数,输出应付款的金额数。解:设X为订购套数,Y为付款金额,贝リ:_150*X(X>100){如果X>100就用Y=5〇・X计算}丫リ8〇・X(X<=100){否则用Y=8〇・X计算}①输入X;②判断X值;③根据判断结果选择符合条件的那种方法计算Y值;④输出计算结果。Pasca!程序:ProgramExam21;Varx»y:integer;BeginWrite(*X=*);Readln(x);{输入X}ifx>100theny:=50*Xelsey:=80*X;{条件判断与选择}Writeln('yゴ,y);ReadlnEnd.程序中的if语句常称为条件语句,它的一般格式为:(1)if条件then语句;(2)if条件then语句Ielse语句2;IF语句的功能是按条件在两种可能中选择其中一种。习惯上把if后面的表达式称为条件,then后面的语句称为真项,else后面的语句称为假项。若条件成立(为真)就执行真项,然后执行if语句的后继语句;若条件不成立(为假)就跳过真项而执行假项,然后执行后继语句。而第一种格式只有真项,没有假项,当条件不成立(为假)就什么也不需做,直接往下去执行后继语句。
10[例2.2]读入三个不同的数,编程按由小到大的顺序排列打印出来。解:设读入的三个数为a,b,c,为了把较小的数排在前面,可作如下处理:①如果a>b就交换a、b的值,②如果a>c就交换a、c的值,③如果b>c就交换b、c的值,④输出处理后的a,b,c。Pasca!程序:ProgranmExam22;Vara,b»c,t:Real;将较大的值换至后面将较大的值换至后面;将较大的值换至后面BeginWrite('Inputa,b,Readln(a,b,c);ifa>bthenbegint:=a;a:=b;end;ifa>cthenbegint:=a;a:=c;end;ifb>cthenbegint:=b;b:=c;end;Writeln('a,b,c:\0=');{复合语句}b:=t(交换a,b]{复合语句}c:=t{交换a,c]{复合语句}c:=t{交换b,c]a:6,b:6»c:6);ReadlnEnd.if语句规定它的真项或假项位置上只能是一个基本语句,如果需要写ー组语句,就应当使用复合语句。本程序中有三处用到更合语句。每个复合语句的范围是从Begin开始到与它相对应的End为止。复合语句的地位和一个基本语句相同;其一般格式为:Begin语句系列End;习题2.11.假设邮局规定寄邮件时若每件重量在1公斤以内(含1公斤),按每公斤1.5元计算邮费,如果超过1公斤时,其超出部分每公斤加收08元。请编程序计算邮件收费。2.输入三个正整数,若能用这三个数作为边长组成三角形,就计算并输出该三角形的面积,否则输出Can'to(组成三角形的条件为:任意两边之和大于第三边)3.输入ー个三位数的整数,将数字位置重新排列,组成一个尽可大的三位数。例如:输入213,重新排列可得到尽可能大的三位数是321。
11第二节情况语句与算术标准函数如果有多种(两种或两种以上)选择,常用情况语句编程。1前面[例2.1]改成用如下方法来处理。根据题意,付款计算可分为两种情况:①Y=50*X(X>100)②Y=80*X(X<=100)显然,情况①与②的选择取决于X值。假设用N表示“情况值”,暂且先让N=2;如果X>100则N=1;(此题屮N的值只是1或2,且取决于X值)Pasca!程序:ProgramExam21_l;VarX,Y,N:integer;BeginWrite('X=);readln(x);n:=2:{先让n=2}ifX>100thenn:=l;{如果X>100则n=l}Casenof{关于情况处理}1:Y:=50*X;2:Y:=80*X;end;Writeln(Y=',Y);ReadlnEnd.程序中的Case—end语句为情况语句,是多路分支控制,•般格式为:Case表达式of情况常量表1:语句1;情况常量表2:语句2;情况常量表n:语句nend;执行情况语句时,先计算Case后面表达式的值,然后根据该值在情况常量表中的“对应安排”,选择其对应的语句执行,执行完所选择语句后就结束Case语句;如果常量表中没有一个与表达式值对应的语句,则什么也不做就结束本Case语句。Case语句的另一种应用格式为:Case表达式of情况常量表1:语句1;情况常量表2:语句2;情况常量表n:语句n;
12else语句n+1end;这种格式的前面部分是相同的,所不同的是:如果常量表中没有一个与表达式值对应的语句,则执行与else对应的语句,然后结束Case语句。[例2.2I对某产品征收税金,在产值1万元以上征收税5%;在1万元以下但在5000元以上的征收税3%;在5000元以下但在1000元以上征收税2%;1000元以下的免收税。编程计算该产品的收税金额。解:设x为产值,tax为税金,用P表示情况常量各值,以题意中每1000元为情况分界:P=0:tax=0(x<1000)P=l,2,3,4:tax=x*0.02(1000<=x<5000)P=5,6,7,8,9:tax=x*0.03(5000
13Write(*Number=);readln(x);P:=trunc(x/1000);ifP>9thenP:=10;CasePof0:tax:=0;1..4:tax:=x*0.2;{从1至4作为同一情况处理}5..9:tax:=x*0.3;{从5至9作为同一情况处理}10:tax:=x*0.5end;Writeln('tt=’,tt:5:2);ReadlnEnd.程序中的trunc(x)为取整函数,是Pascal的算术标准函数之一。Pasca!常用的算术标准函数有19个:(1)abs(x)求x的绝对值(Ixl);(2)exp(x)求ex的值;(e为无理数2.71828…)(3)frac(x)求x的小数部分;(4)int(x)求x的整数部分(不舍入,函数值为实型);(5)ln(x)求以e为底的x的对数(logex);(6)odd(x)判断x的奇偶数(当x为奇数时odd(x)值为true,否则为false);(7)ord(x)求x的序号,结果为整型(x为有序类型量);(8)pin值(3.1415926535897932…);(9)pred(x)求x(有序类型)的前趋值;(10)succ(x)求x(有序类型)的后继值;(11)random随机函数,产生〇~1的随机值;(12)random(n)产生〇〜n的随机数(n为word类型,先执行randomize,才能得到随机整数);(13)round(x)求x的四舍五入整数;(14)trunc(x)求x的整数部分(截掉小数部分,结果为整型);(15)sqr(x)求x的平方值(x2);(16)sqrt(x)求x的开平方根值();(17)sin(x)求x的正弦函数(x为弧度);(18)cox(x)求x的余弦函数(x为弧度);(19)arctan(x)正切的反三角函数(x为数值);习题2.21.运输公司计算运费时,距离(S)越长,每公里运费越低,标准如下:如果S<250公里;运费为标准运价的100%
14如果250公里<=S<500公里,运费为标准运价的98%;如果500公里<=SV1000公里,运费为标准运价的95%;如果1000公里<=SV2000公里,运费为标准运价的92%;如果2000公里<=SV3000公里,运费为标准运价的90%;如果S=>3000公里,运费为标准运价的85%;。请编计算运费的程序。1.输入考试成绩,如果获85分以上为A等,获60分〜84分为B等,60分以下为C等,编程输出考试等级。2.某车间按工人加工零件的数量发放奖金,奖金分为五个等级:每月加工零件数N<100者奖金为10元;100<=N<110者奖金为30元;110<=N<120者奖金为50元;120<=N<130者奖金为70元;N>130者为80元。请编程,由键盘输入加工零件数量,显示应发奖金数。
15第三章循环程序在编程中经常遇到需要多次规律相同的重复处理,这就是循环问题。TurboPasca!采用不同的循环方式来实现,常用的环循有三种:for>repeat>while.第一节for循环for循环是ー种自动计数型循环。[例3.1]试打印出1〜20的自然数。解:①用a代表1〜20各数,同时也用a兼作计数,以控制循环次数;②让a从1开始;③输出a;④a自动计数(加1),如果未超越所规定的循环范围则重复步骤③,否则结束循环。Pasca!程序:ProgramExaml2;Vara:byte;Beginfora:=lto20doWritein(a);ReadlnEnd.程序中fora:=1to20doWritein(a);是for循环语句。for循环语句有两种格式:(l)for循环变量:=初值To终值do语句;(2)for循环变量:二初值downto终值do语句;第⑴种格式的初值小于等于终值,循环变量值按自动加1递增变化;第(2)种格式的初值大于或等于终值,循环变量值按自动减1递减变化。for循环是(以递增1或以递减!)计数型循环。比如:若将[例3.1]程序改为倒计数(递减)循环,则输出2〇〜1的自然数数:ProgramExam31;Vara:byte;Beginfora:=20downto1doWriteln(a);
16ReadlnEnd.[例3.2]打印出30至60的偶数。]解:方法一:①设a表示30至60的所有的数,可用for循环列出;②用式子amod2=0筛选出其中的偶数并输出。Pasca!程序:Programex32;Vara:integer;BeginFora:=30to60doIf(amod2=0)thenwriteln(a);Readln;End.在这个程序中,for循环后的循环语句是ー个条件分支语句。方法二:我们知道,在式子a=2*n中,若n取自然数1、2、3、…,时,则a依次得到偶数2、4、6、…。因此要想得到30至60的偶数,就可以让上面式子中的n取15至30的自然数就可以了。所以本题还可以按以下步骤处理:①设n表示15至30的所有自然数,可用for循环列出;②用式子a:=2*n求出其中的偶数;③将结果输出至屏幕。Pasca!程序:Programex32;BeginForn:=15to30doBegina:=2*n;Writeln(a);End;Readln;End.[例3.3]自然数求和:编ー个程序,求从1至100的自然数的和。解:①令S=0;②令a表示1至100的自然数,用循环列出:③将这些自然数用公式S:=S+a逐一累加到S中去;④循环结束后,S即为1至100的自然数的和,输出即可。Pasca!程序:
17Programex33;vars,a:integer;BeginS:=0;Fora:=1to100doS:=S+a;WritelnCS=\S);Readln;End.[例3.4]ー个两位数x,将它的个位数字与十位数字对调后得到ー个新数y,此时y恰好比x大36,请编程求出所有这样的两位数。解:①用for循环列举出所有的两位数,x为循环变量;②用公式a:=xdiv10分离出x的十位数字:③用公式b:=xmod10分离出x的个位数字;④用公式y:=b*10+a合成新数y;⑤用式子y-x=36筛选出符合条件的数x并输出。Pasca!程序:Programex34;BeginForx:=10to99doBegina:=xdiv10;b:=xmod10;y:=b*10+a;ify-x=36thenwriteln(x);End;Readln;End.[例3.5]把整数3025从中剪开分为30和25两个数,此时再将这两数之和平方,(30+25-=3025计算结果又等于原数。求所有符合这样条件的四位数。解:设符合条件的四位数为N,它应当是ー个完全平方数,用(a*a)表示。①为了确保N=(a*a)在四位数(1000-9999)范围内,可确定a在32〜99循环:②计算N=a*a;将四位数N拆分为两个数nl和n2;③若满足条件(nl+n2)*(nl+n2)=N就输出N。Pasca!程序:ProgramExam35;VarN,a,x,nl,n2:Integer;Begin
18fora:=32to99dobeginN:=a*a;nl:=Ndiv100;{拆取四位数的前两位数}n2:=N-nl*100;{拆取四位数的后两位数}X:=nl+n2;ifx*x=Nthenwritein(N);end;ReadlnEnd.[例3.6]用“*”号打印出如下的长方形图案。解:①上面给出的图例共有4行,我们可以用一个循环控制行的变化;②在每行中又有9歹リ,我们可以在前面控制行的循环中再套一个循环来控制列的变化。Pasca!程序:Programex36;{外循环控制行的变化}{内循环控制列的变化}{输出一行的“*”后换行}BeginFora:=1to4doBeginForb:=1to9dowrite。*');Writein;End;Readln;End.程序中的循环对于a的每个值都包含着一个b=(l〜9)次的内循环。外循环fora将内循环forb包含在里面,称为for循环的嵌套。嵌套形式如:fora:=n1ton2doforb:=mltom2do循环体语句:[例3.7J打印出九九乘法表:解:设a为被乘数,范围为1〜9;b为乘数,范围为1〜a;乘式为a*b=(ab的乘积),则a=l:b=l〜a1*1=1a=2:b=l〜a2*1=22*2=4a=3:b=l〜a3*1=33*2=63*3=9a=4:b=l〜a4*1=44*2=84*3=134*4=16a=9b=l〜a9*1=99*2=18…9*9=81⑴从上面分解的横行中看到共有9行,这里的“行”数变化与a的变化从1〜9相同,可用a控制“行”的循环;
19⑵每“行”里面相乘的次数与b的范围相关,由b控制每“行”里面的“内部”循环:(3)内循环被包含在最里层,执行完每“行”的内部循环,就到下ー“行”去执行新“行”里面的循环,每“行”都拥有形式相同的(b=l〜a)内循环。即每到ー“行”都要执行该“行”的内循环。这里所指的“行”可以理解成抽象的行,不一定是实际上具体对应的行,可以是ー个处理“块”。Pasca!程序:ProgramExam37;Vara,b:byte:Beginfora:=lto9do{外循环}beginforb:=1toado{内循环)write(a,'*',b,'=',a*b,9':3);writeinend;ReadlnEnd.根据这种格式还可以实现多层循环嵌套,例如:fora:=nlton2doforb:=mltom2doforc:=kltok2do循环体语句;[例3.8]从七张扑克牌中任取三张,有几种组合方法?请编程输出所有组合形式。解:设每次取出三张分别为a,b,c„用三重循环分别从1〜7的范围里取值;为了排除取到重号,用(a-b)*(b-c)*(a-c)<>0进行判断。Pasca!程序:programExam38;constn=7;vara,b,c,t:integer;Begint:=0;fora:=1tondoforb:=ltondoforc:=ltondoif(a-b)*(b-c)*(a-c)<>0thenBegininc⑴;writein(a:3,b:3,c:3)End;
20writein(total:,t:5);readlnEnd.[例3.9]数学上把除了1和它本身,没有别的数能够整除它的自然数叫做素数(或质数)。现在由健盘输入ー个自然数N,编程判断N是否是素数,是则输出“Yes”,否则输出“N。”。解:根据定义,对于给定的自然数N,只需判断除1和它本身外,还有没有第三个自然数即可。①令K从1循环至N;②根据NmodK是否为0可统计K的约数的个数;③若N的约数的个数超过2个,则判定N不是素数。Pasca!程序:ProgramExam39;Varn,m»k,t:integer;Beginwrite(‘N二');ReadLn(N);t:=0;fork:=ltoNdo{外循环}ifNmodk=Othent:=t+1;{如果N是奇数}ift>2thenwriteln('No')elsewriteln('Yes');Readln;End.程序中的变量yse为布尔(或逻辑)类型(Boolean)。布尔值只有两个:True(真)False(假)布尔值与条件判断结果为真(条件成立)或为假(条件不成立)的作用相同,常用于条件语句和循环语句中。上面程序中用ifyesand(tmod7=0)thenwritein:实现每行打印七个素数换行,程序中布尔变量yes为真,在逻辑上表示是素数;关系式(tmod7=0)的值为真时,表示该行输出素数巳是7个;用and将这两个“条件”连起来是作一种布尔(逻辑)运算。Pasca!共有四种逻辑运算符;①and(与)两条件都为True时,其结果值为True;否则为False;②or(或)两条件中只要有一个为True;其结果值为True;否则为False;③xor(异或)两条件的逻辑值不相同时,其结果值为True;否则为False;④not(非)条件为True时,其结果值为False;否则为True;(取反)习题3.1:1.打印出1至20的平方数表。2.打印出100至200之间的奇数。3.鸡兔同笼(用for循环程序完成)
211.ー辆快车和一辆慢车开往同一地点,快车票价为18元,慢车票价为13.5元,共售出400张,共计5940元,求快车票和慢车票各多少张?.2.求出能被5整除的所有四位数的和。3.在下面式子中的ニ个口内填入一个合适的同样的数字,使等式成立。□3*6528=3ロ*82564.有一个三位数,它的各位数字之和的11倍恰好等于它自身,请编程求出这个三位数。5.在自然数中,如果一个三位数等于自身各位数字之立方和,则这个三位数就称为是水仙花数。如:153=1ゝ53+33,所以153是ー个水仙花数。求所有的水仙花数。6.编程序打印出下列图案:平行四边形等腰三解形菱形7.编程打印出如下图案:12223333344444445555555558.有三种明信片:第一种每套ー张,售价2元;第二种每套ー张,售价4元;第三种每套9张,售价2元。现用100元钱要买100张明信片,要求每种明信片至少要买ー套,问三种明信片应各买几套?请输出全部购买方案。9.某人想把一元钱换成伍分、贰分、壹分这样的零钱,在这三种零钱中每种零钱都至少各有一个的情况下,共有多少种兑换方案。并打出这些方案。10.11.输出100以内的全部素数,要求每行显示5个。12.A、B两个自然数的和、差、积、商四个数加起来等于243,求ん、B两数。13.百钱买百鸡;今有钱100元,要买100只鸡,公鸡3元一只,母鸡1元一只,小鸡1元3只,若公鸡、母鸡和小鸡都至少要买1只,请编程求出恰好用完100元钱的所有的买鸡方案。第二节repeat循环Repeat循环是直到型循环。试将上一节的例3.1(打印出1~20的平方数表)程序改为repeat循环:ProgramExam31_l;Vara:byte;Begin
22a:=l;writein('a,:8,1a*a*:8);repeatwritein(a:8,a*a:8);inc(a);{改变a的值}Untila>20;ReadlnEmd.程序中的Repeat循环格式为:repeat循环体语句;until条件表达式;{直到条件为真)Repeat循环首先执行由Repeat和Until括起来的循环体语句,然后检查Until后面的条件表达式:如果表达式结果为假,则继续执行循环体,接着继续检查Until后面的条件表达式,如此反复执行直到这个表达式结果为真时结束循环。Repeat循环体语句必须有能改变Until后面条件表达式值的语句,并最终使这个条件表达式的值为真,使循环自动结朿。程序中inc(a)指令相当于a:=a+l,常用的同类指令格式如下:(1)inc(x)等同x:=x+l;(2)inc(x,n)等同x:=x+n;(3)dec(x)等同x:=x—1;(4)dec(x,n)等同x:=x—n;[例3.10]求两个自然数M和N的最大公约数。解:若自然数a既是M和约数,又是N的约数,则称a为M和N的公约数,其中最大的称为最大公约数。为了求得最大公约数,可以从最大可能的数(如M或N)向下寻找,找到的第一个公约数即是最大公约数。Pasca!程序:Programex310;Begina:=N+1;Repeata:=a-1;Until(Mmoda=0)and(Nmoda=0);writeln(a);Readln;End.[例3.11]校体操队到操场集合,排成每行2人,最后多出1人;排成每行3人,也多出1人;分别按每行排4,5,6人,都多出1人;当排成每行7人时,正好不多。求校体操队至少是多少人?
23解:①设校体操队为X人,根据题意X应是7的倍数,因此X的初值为7,以后用inc(x,7)改变X值;②为了控制循环,用逻辑变量yes为真(True)使循环结束;③如果诸条件中有一个不满足,yes的值就会为假(false),就继续循环。Pasca!程序:programExam311;varx:word;yes:boolean;beginx:=0;repeatyes:=true;inc(x,7);ifxmod2<>1thenyes:=false;ifxmod3<>1thenyes:=false;ifxmod4<>1thenyes:=false;ifxmod5<>1thenyes:=false;ifxmod6<>1thenyes:=false;untilyes;{直到yes的值为真}writeln(,Al!:',x);readlnend.程序中对每个X值,都先给Yes赋真值,只有在循环体各句对X进行判断时,都得到“通过”(此处不赋假值)才能保持真值。[例3.12]从键盘输入ー个整数X(X不超过10000),若X的各位数字之和为7的倍数,则打印‘'Yes",否则中打印''No”。解:本题考察的是数字分离的方法,由于X的位数不定,所以以往的解法不能奏效,这是介绍ー种取余求商法。(1)用Xmod10分离出X的个位数字;(2)用Xdiv10将刚分离的个数数字删除,并将结果送回给X;(3)重复(1)(2)直到X=0。Pasca!程序:Programex!2;varx,a,s:integer;begins:=0;repeata:=xmod10;x:=xdiv10;s:=s+a;untilx=0;ifsmod7=0thenwriteln('Yes')
24elsewriteln('No');Readln;end;[例3.13]求1992个!992的乘积的末两位数是多少?解:积的个位与十位数只与被乘数与乘数的个位与十位数字有关,所以本题相当于求1992个92相乘,而且本次的乘积主下一次相乘的被乘数,因此也只需取末两位参与运算就可以了。Pasca!程序:Programex313;vara,t:integer;Begina:=1;t:=0;repeatt:=t+1;a:=(a*92)mod100;untilt=1992;writeln(a);Readln;End.[例3.14]尼科彻斯定理:将任何ー个正整数的立方写成一组相邻奇数之和。如:3コ=7+9+11=2743=13+15+17+19=64解:从举例中发现:(1)ペ正好等于n个奇数之和;(2)n个奇数中的最小奇数是从1开始的奇数序列中的第m个奇数,与n的关系为:m=n(n—1)/2+!〇(3)奇数序列中第m个奇数的值为x,且x=2m—1,比如:n=3时,m=3(3-1)/2+1=4,
25即3个奇数中最小的奇数是奇数序列中的第4个,它的值为x=(2m-l)=7,所以:33=7+9+11。(4)从最小的奇数值x开始,逐个递增2,蹴n个,用t从1开始计数,直到t=n为止。Pasca!程序:ProgramExam35;Varn»m,x,t,s:Beginwrite('inputn/);m:=(n*(n-l)div2)+1;x:=2*m-l;t:=l;write(n'n,'*'integer;readln(n);{输入N}{找到第m个奇数}{算出第m个奇数的值x,是所求的第一个}n.s:=x;ifn>1thenRepeatinc(x,2);write('+',x);inc(t);inc(s»x);Untilt=n;Writein('=\s);ReadlnEnd.=',x);{输出第一个}{用S计算和}{计算下一个奇数}{加上下一个奇数}{计个数并累加和){直到n个}[例3.15]猜价格:中央电视台的“幸运52”栏目深受观众喜爱,其中的“猜商品价格”的节目更是脍炙人口,现在请你编・个程序模拟这ー游戏:由计算机随机产生200至5000之间的ー个整数,作为某件商品的价格,然后由你去猜是多少,若你猜的数大了,则计算机输出提示“Gao”,若你猜的数小了,则计算机输出提示“Di”,然后你根据提示继续猜,直到你猜对了,计算机会提示“Ok”,并统计你猜的总次数。解:本题的游戏规则大家都清楚,要完成程序,必须把处理步骤理清:(1)用随机函数Random产生200至5000之间的ー个整数X;(2)你猜一个数A;(3)若A>X,则输出“Gao”;(4)若A 26readln(a);ifa>xthenwriteln('Gao');ifa 27②计算兔的只数T二H-J;③当总脚数(4*T+2*J)<>F就做(J=J+1,T=H-J);④当4*T+2*尸F时,说明所推算的J和T是正确的,应结束循环,并输出T,JoPascal程序:ProgramExam38;ConstH=30;F=90;VarJ,T:integer;Begin{初始时让J从0开始计算}{当条件为真就做do后面的循环体}J:=0;T:=H-J;While4*T+2*JOFdobegininc(J);{递推改变J值}T:=H-J{计算兔的只数}end;WriteinCT=*,T,>':6,‘J=',J);ReadInEnd.程序中采用While当型循环,While循环语句的格式为:While条件式do语句;其中do后面的“语句”是被重复执行的,称为循环体;若循环体是多个语句,必须用begin-end包起来成为复合语句。While循环首先判断条件式,当条件式的值为真就执行do后面的语句(循环体)。While的循环体内也必须包含能改变控制变量取值语句,影响条件式的值,最终使条件式为false(假),才能结束循环。[例3.9]输入任一的自然数A,B,求A,B的最小公倍数。解:这里采用适合计算机查找的方法:设D是它们的最小公倍数。先找出A,B当中的较大者并存放在A中,将较小者存放在B中,让»=ん当D能够整除B时,则D是所求的最小公倍数;当D不能整除B,就逐次地让D增加A。例如:A=18,B=12,步骤如下:①让D=A(D=18)②当(DmodB)<>0为真时(D不能整除B)就做D=D+A,重复②;③当(DmodB)<>0为假时结束循环,并输出D。Pascal程序:programExam39;vara,b,d,t:word;beginwrite(inputa,b:readIn(a,b);ifa 28writeln(*V,a,',',b,']=',d);readlnEnd.Pascal语言的三种基本循环方式,for循环对循环范围有明确规定,且循环变量只能是递增加1或递减1自动计数控制;而repeat—until循环和while--do循环比较灵活,只要对条件表达式的值能控制满足・定要求就能组成循环,但在循环体中必须有改变循环变量值的语句,使条件判断(逻辑值)最终为True或flase,让循环能够终止。[例3,10]求自然数A,B的最大公约数。解:采用如下方法步骤:(1)求A除以B的余数;(2)当余数V>0就做n=a;a=b;b=nmodb,重复⑴和(2);(3)当余数二0就结朿循环,并输出b值。比如a=18,b=12时,处理步骤为:(1)=,得余数为6;(2)此余数不为零,让a=12,b=6;(3)重复=,得余数为0;(4)结束循环,输出6(余数为零时的b值即是所求的最大公约数)。此方法称为辗转相除法求最大公约数。Pascal程序:programExam310;vara,b,n:word;beginwriteCinputa,b:');readln(a,b);writeCC,a,',',b,')=');whileamodb<>0dobeginn:=a;a:=b;b:=nmodb;end;writeln(b);readlnEnd.[例3.11]将一根长为369cm的钢管截成长为69cm和39cm两种规格的短料。在这两种规格的短料至少各截ー根的前提下,如何截才能余料最少。解:设两种规格的短料分别为:规格为69cm的x根,可在1至(369-39)/69范围循环取值;规格为39cm的y根,用y=(369-69*X)/39)计算;余料R=369-69*X-39*Y。 29①设最小余料的初始值min=369;②在X循环范围内,每ー个X值都计算出对应的丫和R;③如果R 30满足条件A*50+B*35+C*25=225就能确定一组填数。然后选N的下一数值,重复同样的过程。Pascal程序:programexam312;vara,b,c,n,s:integer;beginwriteinCn:3,'a':3,'b':3,'c':3,'s':5);n:=8;whilen<=6dobegina:=0;whilea<=4dobeginb:=0;whileb<=6dobeginc:=n-a-b;ifc>0thenbegins:=50*a+35*b+25*c;ifs=225thenwritein(n:3,a:3,b:3,c:3,s:5);end;inc(b);end;inc(a);end;dec(n);end;readInend.程序运行结果获得两组填数答案。如果改用for循环,程序将更加简明:ProgramExam312_1;Vara,b,c,n,s:Integer;BeginWritein('N':3,'A':3,'B':3,'C:3,forn:=8downto6dofora:=0to4doforb:=0to6dobeginc:=n-a-b;ifc>0thenbegin'st5);{N取值8,7,6I并分别代表甲、乙、丙}{中50环的可能范围}{中30环的可能范围}{计算中25环的子弹数}{如果不是负数}s:=50・a+35*6+25*c;{计算总成绩}ifs=225thenwritein(n:3,a:3,b:3,c:3,s:5);end 31end;readInEnd.习题3.31.求S=1-1/2+1/3-1/4+1/5-1/6+(求前N项的和)2.Faibonacci数列前几项为:0,l,l,2,3,5,8,…,其规律是从第三项起,每项均等于前两项之和。求前30项,并以每行5个数的格式输出。3.小球从100高处自由落下,着地后又弹回高度的一半再落下。求第20次着地时,小球共通过多少路程?4.某登山队员第一天登上山峰高度的一半又24米;第二天登上余下高度的一半又24米;每天均如此。到第七天,距山顶还剩91米。求此山峰的高度?5.给出某整数N,将N写成因数相乘的形式。如:N=12,输出:12=1*2*2*3.6.出售金鱼者决定将缸里的金鱼全部卖出。第一次卖出全部金鱼的一半加二分之一条;第二次卖出剩余的三分之一ー加三分之一条金鱼;第三次卖出余下金鱼的四分之一加四分之ー条;第四次卖出余下的五分之一加五分之一条金鱼。还剩下11条金鱼。当然,出售金鱼时都是整数条,不能有任何破损。求缸里原有的金鱼数?7.外出旅游的几位朋友决定次日早晨共分ー筐苹果。天刚亮,第一个人醒来,他先拿了一个,再把筐里的八分之一拿走;第二个人醒来,先拿两个,再把筐里的八分之一拿走;第三个人醒来,先拿三个,再拿走筐里的八分之一;…每个人依次照此方法拿出各人的苹果,最后筐里的苹果全部拿完,他们每人所拿到的苹果数正巧一样多。求原先筐里的苹果数和人数。8.图中由6个圆圈构成三角形,每条边上有三个圈,将自然数1一6不重复地填入各圆圈位置上,使每条边圆圈上的数字之和相等,请编程输出所有的填法。9.请编程显示出下面数字金字塔图形: 32第四章函数与过程程序中往往需要把主要任务分成若干个子任务,每个子任务只负责ー个专门的基本工作。每个子任务就是ー个独立的子程序。TurboPascal可以把函数和过程作为子程序调用。第一节函数Pascal允许用户在程序中自己说明定义所需要的函数并在程序中调用这些函数。[例4.1]编程找出由键盘任意输入五个整数中的最大整数。解:设输入的五个整数为nl、n2、n3、n4、n5,为了便于处理,引入一个中间变量tl,按如下步骤处理:①令tl=nl;②将tl与n2比较,将两者中较大的数放入tl;③将tl与n3比较,将两者中较大的数放入tl;④将tl与n4比较,将两者中较大的数放入tl;⑤将tl与n5比较,将两者中较大的数放入tl:⑥经过以上5步处理后,tl即为5个数中最大者。从上面规划的步骤看来,从步骤②到步骤⑤需处理的目标是相同的,因此我们可以设计一段子程序Max(xl,x2),以找出xl和x2中最大的值并返回。Pascal程序:ProgramExam41a;Varnl,n2,n3,n4,n5,tl:integer;Functionmax(xl,x2:integer):integer;BeginIfxl>x2thenMax:=xlElseMax:=x2;End;BeginWrite(4Input5numbers:');Readln(nl,n2,n3,n4,n5);Tl:=nl;Tl:=Max(t1,n2);Tl:=Max(tl,n3);Tl:=Max(t1,n4);Tl:=Max(tl,n5);Writeln(4Maxnumber:',tl); 33End.从上例看出,引入函数实际上是将一个复杂的问题划分成若干个易于处理的子问题,将编程化简的一种有效办法,而化简的方法是多种多样的,如前面已经做过求三个数中的最大数,所以可定义ー个专门求三个数中最大数的函数(Max)。第一次用这个函数求出nl,n2,n3三个数中的最大数tl;第二次调用这个函数求出tl与n4,n5三个数中的最大数,也就是前三个数的最大数(已在tl中)和后面二个数再求一次,就得到五个数的最大数。因此,需要两次使用“求三个数中的最大数”,步骤如下:①调用函数Max(nl,n2,n3),求出nl,n2,n3中的最大者tl;②调用函数Max(tl,n4,n5),求出tl,n4,n5中的最大者t2;③输出最大数t2。ProgramExam41_b;Varnl,n2,n3,n4,n5,tl:integer;functionMax(xl,x2,x3:integer):integer;VarXX:integer;beginifX1>X2thenXX:=X1elseXX:=X2;ifX3>XXthenXX:=X3;Max:=XXend;BeginWrite(*Input5numb:');Readln(nl,n2,n3,n4,n5);tl:=Max(nl,n2,n3);tl:=Max(n4,n5,tl);Writein('MaxNumber:',tl);ReadIn(自定义函数Max}{函数内部变量说明}{函数体}{主程序){输入五个数}{用函数求nl,n2,n3的最大数}{用函数求n4,n5,tl的最大数}End.主程序中两次调用自定义函数。自定义函数的一般格式为:function函数名(形式参数表):类型;{函数首部}局部变量说明部分;begin语句系列;{函数体}end;函数中的形式参数接受调用函数时所传入的值,用来参与函数中的运算。[例4.2]求任意输入的五个自然数的最大公约数。解:(D自定义ー个专门求两自然数的最大公约数的函数GCD; 34⑵调用自定义函数,第一次求前两个数的最大公约数;从第二次开始,用每次求得的最大公约数与下ー个数再求两个数最大公约数,直到最后。本题共四次“求两个数的最大公约数”,设输入的五个自然数分别是al,a2,a3,a4,a5,采用如下步骤:①求al,a2两个数的最大公约数一存入al;②求al,a3两个数的最大公约数一存入al;③求al,a4两个数的最大公约数—存入al;④求al,a5两个数的最大公约数一存入al;⑤输出al,此时的al已是五个数的最大公约数。Pascal程序:ProgramExam42;Varal,a2,a3,a4,a5:integder;functionGCD(x,y:integer):integer;{自定义函数}Varn:integer;beginWhilexmody<>0dobeginn:=x;x:=y;y:=nmodyend;GCD:=yend;Begin{主程序}Write(input5Numper:1);readln(al,a2,a3,a4,a5);{输入五个数}Write('C,al,',',a2,',',a3,し',a4,',',a5,')=');al:=GCD(al,a2);{调用函数GCD}al:=GCD(al,a3);al:=GCD(al,a4);al:=GCD(al,a5);Writein(al);readInEnd.函数的结果是ー个具体的值,在函数体中必须将所得到的运算结果赋给函数名;主程序通过调用函数得到函数的运算结果。调用函数的一般格式为:函数名(实在参数表)调用函数时,函数名后面圆括号内的参数必须有确定的值,称为实在参数。调用时即把这些实际值传送给函数形参表中的相应形参变量。函数不是单独的语句,只能作为运算赋值或出现在表达式中。习题4.1 351.数学上把从1开始的连续自然数相乘叫做阶乘。例如把1*2*3*4*5称作5的阶乘,记为5!。编写ー个求n!的函数,调用此函数求:D=2.求从键盘输入的五个自然数的最小公倍数。3.哥德巴赫猜想的命题之一是:大于6的偶数等于两个素数之和。编程将6〜100所有偶数表示成两个素数之和。4.如果一个自然数是素数,目.它的数字位置经过对换后仍为素数,则称为绝对素数,例如13。试求出所有二位绝对素数。第二节自定义过程自定义函数通常被设计成求一个函数值,ー个函数只能得到ー个运算结果。若要设计成能得到若干个运算结果,或完成一系列处理,就需要自定义“过程”来实现。[例4.3]把前面[例2.2](输入三个不同的整数,按由小到大排序)改为下面用自定义过程编写的Pascal程序:Programexam43;Vara,b,c:integer;{自定义交换两个变量值的过程}VartBegin:integer;t:=end;x;x:=y;y:=t{过程体}{交换两个变量的值ProcedureSwap(varx,y:integer);{主程序}{调用自定义过程}BeginWrite('inputa,b,c=’);Readln(a,b,c);ifa>bifa>cifb>cWriteinthenswap(a,b);thenswap(a,c);fhenswap(b,c);(a:6,b:6,c:6);ReadInEnd.程序中ProcedureSwap是定义过程名,从作用来看,过程与函数是相似的,都能将复杂的问题划分成一些目标明确的小问题来求解,只不过函数有值返回而过程则没有。自定义过程的一般格式如下:Procedure过程名(形式参数表);{过程首部}局部变量说明部分; 36语句部分;end;{过程体部分}[例4.4]如果一个自然数除了1和本身,还有别的数能够整除它,这样的自然数就是合数。例如15,除了1和15,还有3和5能够整除,所以15是合数。14,15,16是三个连续的合数,试求连续十个最小的合数。解:从14,15,16三个连续合数中可看出,它们正好是两个相邻素数13和17之间的连续自然数,所以求连续合数问题可以转化为求有一定跨度的相邻两个素数的问题。因此,求连续十个最小的合数可用如下方法:①从最小的素数开始,先确定第一个素数A;②再确定与A相邻的后面那个素数B;(作为第二个素数);③检查A,B的跨度是度否在10以上,如果跨度小于10,就把B作为新的第一个素数A,重复作步骤②;④如果A、B跨度大于或等于10,就打印A、B之间的连续10个自然数,即输出A+l,A+2,A+3A+10oPascal程序:Programexam44;vara,b,s,n:integer;yes:boolean;proceduresub(x:integer;varyy:boolean);vark,m:integer;begin{过程:求x是否为素数}{用yy逻辑值转出}k:=trunc(sqrt(x));form:=3tokdoifodd(m)thenifxmodm=0thenyy:=false;end;begin{主程序}b:=3;repeata:=b{a为第一个素数}repeatyes:=true;inc(b,2);sub(b,yes);ifyesthens:=b-a;{b是a后面待求的素数}{调用SUB过程来确认b是否为素数}{如果b是素数,则求出跨度s}untilyes;untils>=10;forn:=a+ltoa+10do 37write(n:6);writein;readlnend.程序中的过程SUB,用来确定b是否为素数。过程名后面圆括号内的变量是形式参数,简称为形参。过程SUB(x:integer;Varyy:boolean)中的x是值形参,而前面冠有Var的yy是变量形参。值形参只能从外界向过程传入信息,但不能传出信息;变量形参既能传入又能传出信息。本程序过程SUB中的x是由调用过程的实在参数b传入值,进行处理后,不需传出;而yy是把过程处理结果用逻辑值传出,供调用程序使用。试把[例4.3]程序中的过程SWAP(Vaix,y:integer),将x,y前面的Var去掉,就变成了纯粹的值形参,就不能将过程所处理的结果传出去,也就无法得到处理后的结果,通过运行程序比较,可以非常明显地看到值形参和变量形参的区别。调用过程的格式为:过程名(实在参数表);调用过程名后面圆括号内的实在参数与定义过程的形参表必须相对应,调用过程相当于ー个独立语句,可单独使用。[例4.5]将合数483的各位数字相加(4+8+3)=15,如果将483分解成质因数相乘:483=3*7*23,把这些质因数各位数字相加(3+7+2+3),其和也为15。即某合数的各位数字之和等于它所有质因数的各数字之和。求500以内具有上述特点的所有合数。解:①设n为所要求的合数,让n在1〜500间循环做以下步骤;②用tl,t2分别累计合数n及n的质因数的各位数字之和,初值均为〇;③调用过程SUB3进行非素数判定,以布尔变量yes的真假值判定是否,yes的初值为true,如果为(nottrue)非素数,就做步骤④,⑤,⑥;否则取新的n值,重复步骤③;④调用SUB1,求n的各数字之和,传送给tl;⑤调用SUB2,求n的各质因数,对于每个质因素都通过SUB1求它各位数字之和,将所有各质因数字传送给t2。⑥如果tl=t2(各位数字之和等于它所有质因数的各数字之和),则输出此n。PASCAL程序:programexam45;varn,tl,t2,tatol:integer;yes:boolean;proceduresubl(x:integer;vart:integer);{过程:分离x的各位数字}begin{并求各位数字之和}repeatt:=t+xmod10;x:=xdiv10;untilx=0end; 38{过程:分解质因数}proceduresub2(x:integer;vart:integer); 39varxx,tt:integer;beginxx:=2;whilex>ldoifxmodxx=0thenbegintt:=O;subl(xx,tt);t:=t+tt;x:=xdivxxendelseinc(xx)end;proceduresub3(x:integer;varyy:boolean);{过程:判断x是否为素数vark,m:integer;begink:=trunc(sqrt(x));form:=2tokdoifxmodm=0thenyy:=false;end;beginforn:=lto500dobegintl:=0;t2:=0;yes:=true;sub3(n,yes);ifnotyesthenbeginsubl(n,11);sub2(n,t2);iftl=t2thenwrite(n:6);end{主程序}{调用过程求素数}{如果非素数就…}{调用过程求n的各位数字之和}{调用过程求n的各质因数的数字之和《打印合格的合数}end;readInend.程序定义了三个过程SUB1,SUB2,SUB3,其中SUB2过程中又调用了SUB1。在过程中定义的变量或参数,只在本过程内部使用有效。这些变量称为局部变量。如SUB2中的xx只在SUB2中使用,属于局部变量。 40习题:4.21.输入自然数n,求前n个合数(非素数),其素因子仅有2,3»或5。2.自然数a的因子是指能整除a的所有自然数,但不含a本身。例如12的因子为:1,2,3,4,6。若自然数a的因子之和为b,而且b的因子之和又等于a,贝臓a,b为ー对“亲和数”。求最小的ー对亲和数。3.求前n个自然数的平方和,要求不用乘法。例如:3的平方不用3*3,可用3+3+3。4.试用容积分别为17升、13升的两个空油桶为工具,从大油罐中倒出15升油来,编程显示出具体的倒油过程。5.如果一个数从左边读和从右边读都是同一个数,就称为回文数。例如6886就是ー个回文数,求出所有的既是回文数又是素数的三位数。6.任何大于2的自然数都可以写成不超过四个平方数之和。如:8-22+22;14-12+22+32由键盘输入自然数N(2 41第五章Pascal的自定义数据类型Pascal系统允许用户自定义的数据类型有:数组类型、子界类型、枚举类型、集合类型、记录类型、文件类型、指针类型。第一节数组与子界类型[例5.1]总务室在商店购买了八种文具用品,其数量及单价如下表:序号12345678品名圆珠笔铅笔笔记本订书机计算器三角板圆规文件夹件数24110601626323242单价1.180.451.88.878.503.284.202.16编程计算各物品计价及总计价。解:表中有两组数据,设表示物品件数的ー组为a,表示物品单价的ー组为b。a,b两组数据以序号为关联,具有相应的顺序关系。按如下方法处理:①定义s,a,b三个数组,按相应顺序关系,给a,b赋值(件数和对应单价);②每读入ー对数据(件数和对应单价),以同一序号的件数和对应单价计算出同一物品的计价:s[i]=a[i]*b[i];{用s[i]记入第i种物品的计价}t=t+s[i]{用简单变量累加总计价}③循环做步骤②,做完后输出s数组所记入的各物品计价及总计价t。Pascal程序:ProgramExam51;Vara:array[1..8]ofinteger;s,b:array[1..8]ofreal;t,real;i:integer;Begint:=0;fori:=lto8dobeginwriteCa[',i,']=');Readln(a[i]);write('b「,i,']=');readln(b[i]);{a数组为整数型}{s和b数组为实数型){输入并计算八种物品}{输入单价}{输入件数} 42s[i]:=a[i]*b[i];t:=t+s[i]end;writeCi*:2,'':2);fori:=1to8dowrite(i:8);writeln;write('a':2,'':2);fori:=lto8dowrite(a[i]:8);writeIn;write('b':2,'':2);fori:=lto8dowrite(b[i]:8:2);writeIn;write('s':2,'':2);fori:=1to8dowrite(s[i]:8:2);writeIn;writein('Totol=',t:8:2);Read1n{打印物品序号}{输出项宽度为8}{输出项宽度为2}{打印物品件数a数组}{输出项宽度为8}{换行}{打印物品件数b数组}{输出项宽度为8,小数2位}(换行}{打印物品计价s数组}{输出项宽度为8,小数2位}{换行}{打印总价t}end.输出语句为write(实数:n:m)的形式时,则输出该实数的总宽度为n,其中小数m位,此时的实数不以科学计数形式显示。程序中用来表示如物品件数和物品单价等属性相同的有序数据,Pascal语言把它归为数组。数组成员(分量)称为数组元素。数组必须在说明部分进行定义:确定数组名,数组分量(元素)的个数及类型。一般格式有:Var数组名:array[下标类型]of数组元素类型;本程序中a数组和b数组中8个元素的数据都是已知数据,可当作常量,用常量说明语句给数组元素赋初值,所以上面的程序Exani51可改为如下形式:ProgramExam511;consta:array[1..8]ofinteger=(24,110,60,16,26,32,32,42);{给a数组赋初值}b:array[1..8]ofreal=(1.18,0.45,1.80,8.8,78.50,3.28,4.20,2.16);{给b数组赋初值}Vars:array[1..8]ofreal;t:real;i:integer;Begint:=0;fori:=1to8do 43begins[i]:=a[i]*b[i];t:=t+s[i]end;writeCi*:2,''⑵;fori:=lto8dowrite(i:8);'⑵;dowrite(a[i]:8:);writeln;write(a:2,fori:=lto8writeIn;write('b':2,'':2);fori:=lto8dowrite(b[i]:8:2);writeIn;write('s':2,'':2);fori:=lto8dowrite(s[i]:8:2);writeIn;writein('Totol=',t:8:2);ReadInend.数组常量说明格式为:Const数组名:array[下标类型]of数组元素类型=(常量表);程序中对数组的输入、输出处理,常用循环语句控制下标,进行有序地直接操作每个数组元素。[例5.2]编程输入十个正整数,然后自动按从大到小的顺序输出。解:①用循环把十个数输入到A数组中:②从A[l]到A[10],相邻的两个数两两相比较,即:A[l]与A[2]比,A[2]与A[3]比,……A[9]与A[10]比。只需知道两个数中的前面那元素的标号,就能进行与后ー个序号元素(相邻数)比较,可写成通用形式A[i]与A[i+1]比较,那么,比较的次数又可用1~(n-i)循环进行控制(即循环次数与两两相比较时前面那个元素序号有关);③在每次的比较中,若较大的数在后面,就把前后两个对换,把较大的数调到前面,否则不需调换位置。下面例举5个数来说明两两相比较和交换位置的具体情形:564375和6ヒ匕较,交换位置,排成下行的顺序;654375和4比较,不交换,维持同样的顺序:654374和3比较,不交换,顺序不变65437,3和7比较,交换位置,排成下行的顺序:65473经过(1〜(5-1))次比较后,将3调到了末尾。经过第一轮的1〜(N-1)次比较,就能把十个数中的最小数调到最末尾位置,第二轮比较1〜(N-2)次进行同样处理,又把这ー轮所比较的“最小数”调到所比较范围的“最末尾''位置;……;每进行ー轮两两比较后,其下ー轮的比较范围就减少ー个。最后ー轮仅有一次 44比较。在比较过程中,每次都有一个“最小数”往下“掉”,用这种方法排列顺序,常被称之为“冒泡法”排序。Pascal程序:ProgramExam52;constN=10;{定义数组}{交换两数位置的过程}Vara:array[1..N]ofinteger;i,j:integer;procedureSwap(Varx,y:integer);Vart:integer;begint:=x;x:=y;y:=tend;{输入十个数}Beginfori:=ltoNdobeginwrite(i,';{冒泡法排序}{两两相比较}{比较与交换}{输出排序后的十个数}Readln(a[i])end;forj:=ltoN_1dofori:=ltoN-jdoifa[i]Trunc(sqrt(N))为止;⑸打印输出a数组中留下来、未被筛掉的各元素值,并按每行五个数显示。用筛法求素数的过程示意如下(图中用下划线作删去标志):①23456789101112131415—9899100{置数}②23纟5纟789101112131415...9899.100{筛去被2整除的数}③23纟5£789101112131415...9899100{筛去被3整除的数} 4523456789101112131415...9899100{筛去被整除的数}Pascal程序:ProgramExam53;constN=100;typexx=l..N;{自定义子界类型xx(类型名)}Vara:array[xx]ofboolean;i,j:integer;BeginFillchar(a,sizeof(a),true);a[l]:=False;fori:=2toTrunc(sqrt(N))doifa[I]thenforj:=2toNdivIdoa[I*j]:=False;t:=0;fori:=2toNdoifa[i]thenBeginwrite(a[i]:5);inc(t);iftmod5=0thenwriteinend;readInEnd.程序中自定义的子界类型,在用法上与标准类型(如integer)相同,只是值域上界、下界在说明中作了规定,而标准类型的值域由系统内部规定,其上界、下界定义是隐含的,可直接使用。例如:Typeinteger=-32768...32768;Pascal系统已作了标准类型处理,不必再作定义。[例5.4]在一次宴会上,有来自八个不同国家的宾客被安排在同一张圆桌就坐。A是中国人,会讲英语;B是意大利人,他能讲西班牙语;C是英国人,会讲法语;D是日本人,能讲汉语:E是法国人,会讲德语;F是俄国人,懂意大利语;G是西班牙人,能讲日语;最后一个是徳国人,懂俄语。编程序安排他们的座位,使他们在各自的座位上能方便地跟两旁的客人交谈。解:①根据题・)提供条件与数据,建立如下关系代码表:国家名中国意大利英国日本法国俄国西班牙徳国宾客代码ABCDEFGH语言代号12345678 46懂外语代号37518246总代码A13B27C35D41E58F62G74H86表中总代码实际上是前三项代码的归纳:第一个字母表示哪国人;第二个数字表示本国语代号:第三个数字表示懂哪国外语。如A13,A表示中国人,1表示汉语(本国语),3表示会说英语。所以每个宾客的情况均用总代码(三个数据组成的字符串)表示;②定义由8个元素组成的数组(NAME),元素类型为字符串类型(String);③元素的下标号影响各人座位关系,必须满足后ー个元素的下标号应与前一个元素字符串中的第三个数据相同。例如:若第一个位置总代码为A13,则第二个位置应根据A13中最后的3,安排C35。即A与C可以交谈。以此类推。用字符串处理函数COPY,截取字符串的第一个字母作为宾客代码打印,再取第三个字符,用VAL将其转换成数字,将这个数字作为下标号,把这个下标号的元素安排在旁边(相邻);④重复步骤③的方法,安排其后的元素,直到ハ个数据全部处理完为止。Pascal程序:ProgramExam54;{定义字串类型数组并赋常量)constname:array[1..8]ofstring=('A13','B27','C35','D41','E58','F62','G74','H86');Vari,code:integer;x:1..8;s:string;Begins:=copy(name[l],1,1);write(s:4);s:=copy(name[l],3,1);Vai(s,x,code);fori:=lto7do{整数类型}{子界类型}{字符串类型)(截取第一个元素字串的第一个字符}(确定第一个位置}{截取元素字串的第三个字符作为相邻}{将字串s的值转换成数字存入x}{确定后面7个位置}Begin{找到相邻者的代码}{打印相邻者代码}{确定下ー个相邻元素}s:=copy(name[x],1,1);write(s:4);5:=copy(name[x],3,1);Vai(s,x,code);end;readInEnd.Pascal常用的字符串处理标准函数有7个:设变量s,str,strl,str2均为字符串类型(string){多个字符};ch为字符类型(char){单个字符};(1)copy(str,n,m)从字符串str的左边第n个开始截取m个字符;如:copy('Pascal',3,2)的结果为‘sc';(2)concat(strl,str2)将两个字串连接成为ー个新的字串; 47如:s:=strl+str2;同等于两串字符相加(1)Length(str)求字串str的长度(字符个数);(2)chr(x)求x(x为1…255整数)的ASH代码对应的字符;如:chr(65)结果为‘A‘。(3)ord(ch)求字符ch对应的ASCII代码值;如ord('A')结果为65;(4)pos(strl,str2)求字串strl在字串中开始的位置;如:pos('sea'pascal')结果为3;(5)upcase(ch)将字符ch转为大写字母,如upcase('a')结果为'A';Pascal常用的字符串处理标准过程有4个:(1)Vai(str,x,code)将数字型字串转为数字并存入变量x中;如:Vaiぐ768ゝx,code),x值为768,code为检测错误代码,若code=0表示没有错误;(2)str(n,s)将数字n转化为字串存入s中,如str(768,s)s的结果为'768';(3)insert(strl,str2,n)把字串strl插入在字串str2的第n个字符之前,结果在str2中;{此过程中的str2为变量形参,具有传入传出的功能);(4)delete(str,n,m)从字串str的第n个开始,删除m个字符,把剩余的字符存在str中,{此过程中的str为变量形参,具有传入传出的功能};[例5.5]ー个两位以上的自然数,如果左右数字对称,就称为回文数,编程找出所有不超过6位数字的回文数,同时又是完全平方数的数。如121是回文数,又是11的平方,所以是完全平方数。解:①不超过6位数的完全平方数用循环在10〜999范围产生(fori:=10to999);②将完全平方数(i*i)转成字串类型存入s中;③逐个取s的左右字符,检查是否相同(对称),④如果是回文数,就调用打印过程(Print)。ProgramExam55;Varn,k,j,t:integer;s:string;i:longint;ProcedurePrint;beginwrite(s:10);inc(t);iftmod6=0thenwriteinend;检查对数不超过总长度的一半;{字符串类型}{长整数类型}{打印过程(无形参)}{打印S,用t计数){打印6个换行}{将完全平方数转换成字串}{计算字串长度}Begint:=0;fori:=10to999dobeginstr(i*i,s);k:=length(s); 48n:=kdiv2;{计算字串长度的一半}j:=l;whilej<=ndo{取左右字符检查是否对称}ifcopy(s,j,1)<>copy(s,k+l-j.1)thenj:=1000{若不对称让j=1000,退出循环}{j<1000即是回文数,调打印}{打印总个数}elseinc(j);ifj<1000thenPrintend;writein;writeln('Total=':8,t);readInEnd.习题5.11.裴波那契数列:数列1、1、2、3,5、8、13、21…称为裴波那契数列,它的特点是:数列的第一项是1,第二项也是1,从第三项起,每项等于前两项之和。编程输入ー个正整数N,求出数列的第N项是多少?(N不超过30).2.下面的竖式是乘法运算,式中P表示为一位的素数,编程输出此乘法竖式的所有可能方案。PPPPxEPPPPP3.节目主持人准备从N名学生中挑选ー名幸运观众,因为大家都想争当幸运观众,老师只好采取这样的办法:全体同学排成一列,由前面往后面依顺序报数1,2,1,2,-f报单数的同学退出队伍,余下的同学向前靠拢后再重新由前往后1,2,1,2,…报数,报单数者退出队伍,如此下去最后剩下一人为幸运观众。编程找出幸运观众在原队列中站在什么位置±?(N由键盘输入,N<255)。4.1267*1267=1605289,表明等式右边是ー个七位的完全平方数,而这七个数字互不相同。编程求出所有这样的七位数。5.校女子100米短跑决赛成绩如下表,请编程打印前八名运动员的名次、运动员号和成绩。(从第一名至第八名按名次排列)运动员号017168088105058123142055113136020032089010成绩(秒)12.312.613.011.812.113.112.011.911.612.412.913.212.211.46.求数字的乘积根。正整数的数字乘积这样规定:这个正整数中非零数字的乘积。例如整数999的数字乘积为9*9*9,得到729;729的数字乘积为7*2*9,得到126;126的数字乘积为1*2*6,得到12;12从数字乘积为1*2,得到2。如此反复取数字的乘积,直至得到一位数字为止。999的数字乘积根是2。编程输入一个长度不超过100位数字的正整数,打印出计算数字乘积根的每ー步结果。输出格式如下:(N=3486784401)3486784401516096162012 4921.有一组13个齿轮互相啮合,各齿轮啮合的齿数依次分别为6,8,9,10,12,14,15,16,18,20,21,22,24»问在转动过程中同时啮合的各齿到下次再同时啮合时,各齿轮分别转过了多少圈?2.集合M的元素的定义如下:(1)数1属于M;(2)若X属于M,则A=2X+1,B=3X+1,C=5X+1,也属于M;(3)再没有别的数属于M。(M={1,3,4,6,7,9,10,13,15,16....如果M中的元素是按递增次序排列的,求出其中的第201,202和203个元素。3.ー个素数,去掉最高位,剩下的数仍是素数;再去掉剩下的数的最高位,余留下来的数还是素数,这样的素数叫纯粹素数。求所行三位数的纯粹素数。4.自然数4,9,16,25等叫做完全平方数,因为ザ=4,32=9,42=16,52=25,当某一对自然数相加和相减,有时可各得出ー个完全平方数。例如:8与17这对自然数:17+8=2517—8=9试编程,找出所有小于100的自然数对,当加和减该数对时,可各得出ー个完全平方数。第二节二维数组与枚举类型[例5.6]假设四个商店一周内销售自行车的情况如下面表一所示,自行车牌号永久牌飞达牌五羊牌第一商店354055第二商店205064第三商店103218第四商店383628表ー几种牌号自行车的单价如表二所示。求各店本周出售自行车的总营业额。r单价]I[承久牌]395|F飞达牌398|1五羊牌]表二解:①把表一看成是由行(每个店占一行)与列(每种牌号占一列)共同构成的数据组,按表格排列的位置顺序,用A数组表一各数据表示如下:A[l,1]=35A[l,2]=40A[l,3]=55{第一行共三个数据} 50A[2,l]=20A[2,2]=50A[2,3]=64A[3,l]=10A[3,2]=32A[3,3]=18A[4,1]=38A[4,2]=36A[4,3]=28{第二行共三个数据}{第三行共三个数据}{第四行共三个数据}A数组有4行3歹リ,每个数组元素由两个下标号表示,这样的数组称为二维数组。②表二的数据按排列顺序用B数组表示如下:B[l]=395B[2]=398B[3]=384②B数组有3个数据,用ー维数组表示,下标号与表一中列的序号冇对应关系。③计算各店营业额并用T数组表示:T[1]=A[1,1]*B[1]+A[1,2]*B[2]+A[1,3]*B[3]T[2]=A[2,1]*B[1]+A[2,2]*B[2]+A[2,3]*B[3]T[3]=A[3,1]*B[1]+A[3,2]*B[2]+A[3,3]*B[3]T[4]=A[4,1]*B[1]+A[4,2]*B[2]+A[4,3]*B[3]{计算第一商店的营业额}{计算第二商店的营业额}{计算第三商店的营业额}{计算第四商店的营业额}T数组共有4个数据,为ー维数组,下标号与商店号有对应关系。④输出T数组各元素的值。Pasca!程序:ProgramExam56;VarA:array[1..4,1..3]ofinteger;B:array[1..3]ofinteger;T:array[1..4]ofinteger;i,j:integer;Beginfori:=lto4doBeginWrite(lA[l,i,l]:り;forj:=lto3doReadln;end;fori:=lto3doBeginWrite('B[',I,Readln(B[i]);end;fori:=lto4doBeginT[i]:=0;Write。,:5,1:4);forj:=lto3doBeginWrite(A[i,j]:6);{定义二维数组,整数类型}{ー维数组,3个元素}{ー维数组,4个元素}Read(a[i,j]);{输入表一的数据}{提示输入哪一行}{每行3个数据}{输完每行按回车键}{输入表二的数据}{提示第几行}{输入一个数据按回车}{计算并输出} 51T[i]=T[i]+A[i,end;Write(T[i]:8);end;Readln;end.程序中定义二维组方式与一维数组形式相同。二维数组的元素由两个下标确定。二维数组元素的格式如下:数组名[下标1,下标2]常用下标1代表数据在二维表格中的行序号,下标2代表所在表格中列的序号。[例5.7]输入学号从1101至1104的4名学生考试语文、数学、化学、英语'计算机六门课的成绩,编程求出每名学生的平均分,按每名学生数据占一行的格式输出。解:根据题目所给数据及要求,定义如下数据类型:①学生成绩:在数据表格中每人的成绩占一行,每行6列(每科占一列):定义二维数组s,各元素为实型;②个人平均分:定义一维数组av,各元素为实型:③个人总分:是临时统计,为计算机平均分服务,用简单实型变量t;处理步骤为:①用双重循环按行i按列j输入第i个人第j科成绩存入s[i,j];②每读入一科成绩分,就累计到个人总分t中;③输完第i个人的各科成绩,就计算出第i个人平均分并存入数组av(i)中;④重复上述步骤,直到全部学生的成绩处理完毕;⑤用双重循环按行列形式输出完整的成绩表。Pasca!程序:ProgramExam57;constNB=1101;NE=1104;{定义二维数组(学生成绩)}{定义一维数组(平均成绩)}{i为子界类型(学号范围)}{j为子界类型(课程范围)}{t为实数类型(计总成绩)}{用i控制处理一位学生成绩}Vars:array[NB..NE,1.,6]ofreal;av:array[NB..NE]ofreal;i:NB..NE;j:1..6;t:eal;Beginfori:=NBtoNEdobegint:=0;write(i,':');forj:=1to6do{输入并计算每人的6门成绩} 52beginread(s[i,j]);t:=t+s[i,j];end;av[i]:=t/6;readlnend;writein;{累加个人总分}{求个人平均分}{输完6门分按一次回车键}{输出学生成绩表}writein(:5,*****************************************);writeinC':5,'NameChinMathPhysChemEnglCompAve');writein('':5,'');fori:=NBtoNEdobeginwriteC\5,i:4,''⑵;{输出学号}forj:=lto6dowrite(s[i,j]:4:1,''⑵;{输出6门成绩}writeln(av[i]:4:1);{输出平均分}end;readlnEnd.程序中的学生成绩用键盘输入方式赋给二维数组各元素,如果是少量已知数据,也可在常量说明部分,直接给二维数组各元素赋常数,现将本例题改为如下程序:ProgramExam57_l;ConstNB=1101;NE=1104;TypeCou=(Chin,Math,Phys,Chem,Engl,Comp);Num=NB..NE;Consts:array[Num,Cou]ofreal=((87,91,78,85,67,78),(69,84,79,95,91,89),(86,69,79,89,90,88),(88,89,92,87,88,81));Varav:array[Num]ofreal;i:Num;j:Cou;t:real;Beginfori:=NBtoNEdobegint:=0;{定义常量}{自定义枚举类型}(自定义子界类型}{定义二维数组并赋常数){定义ー维数组(平均成绩)}{i为子界类型(学号范围)}{j为子界类型(课程范围)}{t为实数类型(计总成绩)}{用i控制处理一位学生成绩} 53{计算每人的6门成绩}{累加个人总分}{求个人平均分}{输出学生成绩表}forj:=ChintoCompdot:=t+s[i,j];av[i]:=t/6;end;writeIn;writeIn(>':5,'****************************************');writein('':5,'NameChinMathPhysChernEnglCompAve');writeIn('':5,');fori:=NBtoNEdobeginwriteC':5,i:4,'':2);{输出学号}forj:=ChintoCompdowrite(s[i,j]:4:l,*'⑵;{输出6门成绩}writeln(av[i]:4:1);{输出平均分}end;End.程序说明部分定义了枚举类型。枚举类型常用自然语言中含义清楚、明了的单词(看成代码)来表示“顺序关系”,是ー种顺序类型,是根据说明屮的排列先后顺序,オ具有0,1,2-n的序号关系,可用来作循环变量初值和终值,也可用来作数组下标。但枚举类型不是数值常量或字符常量,不能进行算术运算,只能作为“序号关系”来使用。[例5.8]从红(red)、黄(yellow)、兰(blue)、白(white)、黑(black)五种颜色的球中,任取三种不同颜色的球,求所有可能的取法?解:①将五种颜色定义为枚举类型;②a,b,c都是枚举类型中取不同颜色之一;③a的取值范围从redtoblack;b的取值范围从redtoblack,但必须a<>b;c的取值范围从redtoblack,且必须(a<>b)and(c<>b);④每次打印取出的三个球的颜色,即第一个到第三个(forn:=lto3)当n=l:取a的值,根据a的“顺序”值输出对应颜色字符串;当n二2:取b的值,根据b的“顺序”值输出对应颜色字符串;当n二3:取c的值,根据c的“顺序”值输出对应颜色字符串;⑤直至a,b,c的取值范围全部循环完毕。Pasca!程序:programex58;typecolor=(red,yellow,blue,white,black);vara,b,c,dm:color;nn:1..3;s:integer;begin 54s:=0;fora:=redtoblackdoforb:=redtoblackdoifa<>bthenforc:=redtoblackdoif(c<>a)and(c<>b)thenbegininc(s);write(s:5);fornn:=lto3dobegin{找每种球的颜色“顺序”值}{dm是所取得的“顺序”值}{根据“顺序”值打印对应字串}red':9);casennof1:dm:=a;2:dm:=b;3:dm:=cend;casedmofred:write(,yellow:write('yellow':9);blue:write。blue,:9);white:write('white,:9);black:write。bleak,:9);end;end;writeinend;writeIn;writein('totalnum:':12,s:4);readInend.程序中的从red到black的顺序关系本来是不存在的,但经过枚举类型定义之后,就建立了这种“枚举”先后而产生的顺序排列关系。这种“关系”完全取决于类型说明时的位置排列。[例5.9]新录A、B、C三个工人,每人分配ー个エ种,每个エ种只需一人,经测试,三人做某种工作的效率如下表所示。如何分配三人的工作才能使他们工作效益最大? 55解:①定义各元素值为整数型的X数组,将表中的数据按行列关系作如下处理:A为第一行,将其三种工作效率(4,3,3)分别存入(x[A,l],x[A,2],x[A,3]);B为第二行,将其三种工作效率(2,4,3)分别存入(x[B,l],x[B,2],x[B,3]);C为第一行,将其三种工作效率(4,5,2)分别存入(x[C,1],x[C,2],x[C,3])o在这里,x数组第一个下标为枚举型,表示工人(A,B,C);第二个下标为子界型,表示エ种(ー、二、三):X(工人,エ种澤数型1—子界型枚举型②计算三人工作的总效率:S=x[A,i]+x[B,j]+x[C,k]A的工种i:1〜3(用循环fori:=lto3);B的工种j:1〜3(用循环forj:=lto3且jく>i):C的工种k=6-i-j(工种代号总和为6,减去两个代号就得到第三个);③将每次计算得到的S与“最大值"m比较(m的初值为〇),只要有大于m的S值即取代m原来的值,使之最大,同时用数组dd记录最大S值时的工种i,j,k值;④当循环全部结束时,打印记录下来的每个人的工种。Pasca!程序:Programexam59;typema=(a,b,c);wk=l..3;Constx:array[ma,wk]ofinteger=((4,3,3),(2,4,3),(4,5,2));m:integer=0;Vardd:array[wk]ofwk;i,j,k:wk;s:integer;beginfori:=lto3doforj:=lto3doifj<>ithenbegink:=6-i-j;s:=x[a,i]+x[b,j]+x[c,k];ifs>mthenbeginm:=s;dd[l]:=i;{定义枚举类型){定义子界类型}{给X数组(二维)}{赋常量(表中值)}{给m赋初值0}{用DD数组记忆エ种号}{记下最大效益}{记下最佳分配方案}dd[2]:=j; 56dd[3]:=kendend;fori:=lto3do{输出}writeln(chr(64+i):8,dd[i]:8);writein('最大效益:':12,m:4);readInend.输出语句中的chr(64+i)是将(64+i)数值转换成对应的ASCII字符。程序中用枚举类型表示工人代码(A,B,C),比较直观、清晰、易读好理解。在程序中枚举类型都可以用数字序号来取代,下面程序用!,2,3代表工人A,B,C:programexam59_l;typen=l..3;Constx:array[n,n]ofinteger=((4,3,3),(2,4,3),(4,5,2));m:integer=0;Vardd:array[n]ofn;i,j,k:n;s:integer;beginfori:=lto3doforj:=lto3doifj<>ithenbegink:=6-i-j;s:=x[l,i]+x[2,j]+x[3,k];ifs>mthenbeginm:=s;dd[l]:=i;dd[2]:=j;dd[3]:=kendend;fori:=1to3dowriteln(chr(64+i):8,dd[i]:8,x[i,dd[i]]:8);writein('最大效益:':12,m:4);readInend.程序中的x[i,dd[i]]是分配给i号工人做dd[i]号エ种的效率值,在这里,以数组元素值作为下标,称为下标嵌套。 57[例5.10]下面是ー个3阶的奇数幻方。它由1到ガ的自然数组成一个3*3的方阵,方阵的每一行,每一列和两个对角线上的各数字之和都相等,且等于n(n2+l)/2(n是方阵的行数或列数)。编程打印出n为10以内的奇数阶幻方。解:仔细观察示例,有如下规律:①在顶行中间填数字1;{横坐标(行)X=l,纵坐标(列)丫=(n+l)/2}②后继数放在前一个数的左上方:{X=X-1;Y:=Y-1}若超出了行,则认为是最后一行:{ifX<1thenX=n}若超出了列,则认为是最后一列;{ifY<1thenY=n}③若左上方已有数,则放在原数的正下方;{X=X+1,Y=Y}④重复步骤②、③,直至填满方阵为止。Pascal程序:ProgramExam510;UsesCrt;Vara:array[1..10,1..10]ofinteger;x,y,xx,yy,s,n:integer;BeginClrscr;{清屏}fillchar(a,sizeof(a),0);{将a数组各元素置〇}repeatwriteInputNumberPlease!');{提示输入n}readln(n)untilodd(n);s:=l;x:=l;y:=(ndiv2)+1;a[x,y]:=1;repeatinc(s);xx:=x;yy:=y;dec(x);dec(y);ifx 58程序中fillchar(a,sizeof(a),0)是给a数组各元素置〇。Clrscr是清屏。习题5.2:1.输入四个学生考试五门功课,要求按个人总分从高到低排列输出二维成绩表格。(即每行有学号,五科成绩及总分)2.杨晖三角形的第n行对应着二项式n次鼎展开式的各个系数。例如第3行正好是(a+bド二a>3a2b+3ab?+b3展开式各项系数1,3,3,1。右图是n从。〜4的杨晖三角形:1第一行n=0,即(a+b)°=l,系数为1;11第二行n=l,即(a+b)'=a+b,系数为11;第三行n=2,即(a+b)唯aZ+2ab+b「,系数为121;1编程输出n行的杨晖三角形。3.下面是ー个4*4的矩阵,它的特点是:(1)矩阵的元素都是正整数;(2)数值相等的元素相邻,这样,这个矩阵就形成了一级级“平台”,其上最大的“平台’’面积为8,高度(元66671637素值)为6。若有一个已知的N*N的矩阵也具有1667"Maxs=8H=6上面矩阵的特点,求矩阵最大“平台”的面积和bb//高度。4.打印ー个n*n的数字螺旋方阵。这个数字方阵的特点是:以左上角1开始向下,数字以外圈向里按自然数顺序转圈递增,一直到中心位置的が为止。例如n=3:187296345第三节集合类型Pasca!系统把具有共同特征的同一有序类型的对象汇集在ー起,形成•个集合,可将集合类型的所有元素作为ー个整体进行集合运算。[例5.11]用随机函数产生20个互不相同的40到100的随机整数,然后按从小到大顺序打印。解:按以下步骤处理:①为使产生的随机整数互不相同。因此,每产生一个数,都要判断集合中已否包含,如果没有包含,就放到集合中,并统计个数,直到20个。 59②将集合中的数移到数组中,此题利用下标序号从小到大的特征进行映射排序打印。Pasca!程序:ProgramExam511;UsesCrt;Vara:Array[40..100]Ofboolean;dd:setOf40..100;n:Integer;ProcedureInit;Vari,m:Integer;Beginn:=0;dd:=[];repeatbeginRandomize;m:=Random(100);ifnot(mindd)and(m>40begindd:=dd+[m];inc(n)end;enduntiln=20;End;ProcedurePrint;Vari,j,k:Integer;Beginfillchar(a,sizeof(a),false);Fori:=40To100Doifiinddthena[i]:=true;Fori:=40To100DoIfa[i]ThenWrite(i:4);End;BeginClrscr;init;print;RepeatUntilKeyPressed;End.程序中定义了集合类型DD,{定义集合dd}(定义产生并处理随机数的过程)(集合dd初值为空}{将随机发生器作初始化处理}{产生随机整数m})then{把m放入集合dd中}{定义打印过程}{将数组a的各元素置false值}{以集合元素值为下标的数组元素赋真值}{以下标号为序(从小到大)输出}{输出a数组中元素值为真的下标号}{主程序}{产生随机数,并存入集合中}{打印}集合的元素为子界类型。定义集合类型的一般格式是: 60集合的值放在ー对方括号中,各元素用逗号隔开,与排列的顺序无关,因此,[9,2,5]和[2,5,9]的值相等,没有任何元素的集合是空集合,用口表示。如果集合的元素是连续的,可用子界表示,如[5,6,7,8,9]可表示为[5..9].集合的赋值格式为:集合变量名:=集合表达式;集合有以下几种运算:1.集合的交、并、差运算:(设两个集合a:=[l,2,4,6I和b:=[4,6,7,8])①集合的并:a+b即组合成新的集合(为[1,2,4,6,7,8]);②集合的交:a*b即将a,b集合中的公共元素组合成新的集合(为[4,6,]);③集合的差:a-b即在a中的元素去掉在b中出现的之后,所剩下的集合(为[1,2])。2.集合的比较:①相等:a=b,若两个集合中的元素个数相等,每个元素相同,则两个集合相等,比较结果为真(ture),否则为假(false);②不等:a<>b表示两个集合不相等;③包含:a>=b表示a集合包含b集合中的所有元素:a<=b表示a集合是b集合的子集。3.集合的测试运算:检查某个数据在集合中,测试结果为ture;不在集合中,测试结果为false:例如:6in[8,6,9,4]结果为ture;{6在集合[8,6,9,4]中为真}2in[8,6,9,4]结果为false;{2在集合[8,6,9,4]中为假}从程序Exam5U的输出部分可看到,集合类型的值不能直接输出,要用测试方法进行输出或转换成数组元素的值。[例5.12]用集合进行筛法求200以内的素数。解:①将[2..200]放入集合S中;②取S中的第一个元素值nxt,放入集合P中,同时将S中的凡是nxt的倍数的元素全部“划”去;③重复步骤②,直至S集合为空;④用测试运算打印P集合中全部元素值。Pasca!程序:ProgramExam512;Usescrt;constn=200;vars,p:setof2..n;{s,p为集合类型}nxt,j,t:byte;beginclrscr;s:=[2..n];{将[2..n]赋给s} 61p:=[];nxt:=2;t:=0;repeatwhilenot(nxtins)donxt:=succ(nxt);p:=p+[nxt];j:=nxt;whilej<=ndobegins:=s-[j];inc(j,nxt)end;ifnxtinpthenbegininc(t);write(nxt{后继函数}{将nxt放入P中}{筛掉S中的处理过的元素}{用测试运算进行输出}:6);iftmod6=0thenwriteinend;unti1s=[];readInend.集合内的元素个数不能超过255个,如果要用超过255个成员的集合类型求素数,必须用小集合的数组来表示大集合,即把大集合分成若干个小集合,每个小集合只是数组的元素,(数组元素为ー个小集合)整个数组就是ー个大集合。筛法运用在每个数组元素(小集合)中进行。[例5.13]将自然数1一9这九个数分成三组,将每组的三个数字拼成为三位数,每个数字不能重复,且每个三位数都是完全平分数。请找出这样的三个三位数。解:①自定义函数yes,用集合判定九个数字是否有重复,采用逆向思维,假设做邓了三个三位完全平方数:将三个三位完全平方数分离成单个数字放入集合dd中,检查集合dd,如果自然数1〜9每个数恰好都在集合dd中,函数yes赋真(ture);只要有一个不在集合中,九个数字没有占完集合中的九个位置,则必有重复,函数值为假(false),因为集合中对相同数字视为同一成员,如果有重复,则集合中不足9个成员(用测试运算)。②程序用11-31平方产生三位的完全平方数。用循环方式每次取三个数为ー组,存入a数组。③对a数组的三位数调用自定义函数yes处理;④如果函数yes值为真,就打印a数组中的三个数。Pasca!程序:Programexam513;UsesCrt;Vara:Array[1..3]OfInteger;i,j,k,x:Integer;Functionyes;Boolean;{处理是否有重复数字} 62Vari:Integer;d:SetOf0..9;{集合元素为子界类型}Begind:=[];{集合的初值为空集合}Fori:=lTo3Do{将a数组中三个数分离成单个数并放入集合d}d:=d+[a[i]Div100,(a[i]Mod100)Div10,a[i]Mod10];yes:=true;Fori:=lTo9DoIfNot(iInd)Thenyes:=false;{只要有一个不在集合中即为假}End;BeginwriteIn;fori:=llto29doBegina[l]:=i*i;forj:=i+lto30dobegina[2]:二j*j;fork:=j+lto31dobegina[3]:=k*k;IfyesThenForx:=lToendendend;RepeatUntilKeyPressed;End.{在三位完全平方数范围内循环推出三个数}{第一个三位的完全平方数}{第一个三位的完全平方数}{第一个三位的完全平方数}{调用自定义yes函数结果为真就输出}3DoWriteln(x:8,a[x]:8);习题5.31.设计一个将十六进制数转换为十进制数的程序。2.将自然数1-9数字不重复组成三个三位数,且三个数之比为1:2:3«求出能满足条件的全部方案。3.从键盘输入・个20位以内的自然数,然后将组成这个数的各位数字重新排列,得到ー个数值为最小的新数,且新数的位数保持不变。打印出重新排列后的新数。4.现有五件物品,重量分别为4、8、10、9、6.5公斤,它们的价值分别为12、21、24、17、10.5元。有一个背包,装入物品总量不得超过19公斤,该选哪几件物品放入背包内使 63总价值最大?第四节记录类型和文件类型前面介绍的数组类型和集合类型有一个共同点,那就是在同一个数组或集合中的各有元素都必须具有相同的类型。如果要处理如下表所示的学生档案卡片上的数据,各栏目的数据类型不一样(学号,姓名,成绩…),需要用不同的类型表示。学号姓名性别出生年月语文数学英语平均分为此,PASCAL系统定义了记录类型,可用来表示不同类型的数据。[例5.14]建立一张学生情况表格,求出每位学生的平均成绩,并输出这张表格。解:①定义记录类型:Date(表示日期记录,有三个域:day日,mon月,yea年);Studa(表示学生情况记录,有六个域:nu学号,na姓名,dd出生年月,se性别,s成绩,ave平均分);②读入记录数据;③计算学生的平均成绩;④输出记录内容。PASCAL程序;ProgramExam514;Constn=2;m=3;TypeDate=Recordday:1..31;mon:1..12;yea:1970..1999;End;Studa=Recordnu:string[5];na:string[8];dd:Date;se:char;s:array[1..m]ofave:realEnd;Sarr二array[1..n]ofStuda;VarStu:sarr;Procedurerrd(varstu:sarr);{为了简单,人数N=2课目№3}{定义Date(日期)记录类型}{域名day表示天,为子界型(L.31)}{域名mon表示月,为子界型(1.•12)}{域名yea表示年,为子界类型}{定义Studa(学生情况)记录类型}{域名nu表示学号,为字符串类型}{域名na表示姓名,为字符串类型}{域名dd表示日期,为记录类型(Date)}{域名se表示性别,为字符类型}real;{域名s表示成绩,为数组类型}{域名s表示平均分,为实数类型}{定义Sarr为数组类型,各元素为记录类型}{变量Stu为数组(Sab)类型}{定义输入和计算过程} 64{变量a为记录(Studa)类型}vari,k:integer;t:real;a:studa;begin{开域语句,打开当前记录a和dd.进行以下操fork:=ltondobeginwitha,dddo作}beginwrite(k:2,,nu:');readln(nu);{输入学号}write(k:2,,na:');readln(na);{输入姓名}write(k:2,,se:');readln(se);{输入性别}write(k:2,,day:');readIn(day);{输入出生日}write(k:2,,mon:');readIn(mon);{输入出生月}write(k:2,,yea:');readIn(yea);{输入出生年}t:=0;fori:=1tomdo{输入m科的成绩分}beginwrite('s[',i,']=');read(s[i]);{累加总分}{计算平均分}{将当前记录存入stu[k]中}t:=t+s[iend;readln;ave:=t/m;stu[k]:=aend;endend;Procedurevari:printl;integer;{打印表格线}beginfori:=lto60dowritein;end;Procedureprint2;beginwritelnC':18,write(>-');{打印表头和表格栏目}tableprintl;write('num.writein('sexprintl'':6,'name','':7,'mm/dd/yy','':4);,'Chin','':2,'math','':2,'Engl',''vaer'); 65end;Procedureprint3(stu:sarr);{打印记录数据}vari,j:integer;beginprint2;forj:=ltondowithstu[j],dddobeginwrite(nu:5,na:9,'':8,mon:2,'/day:2,yea:4,',write(se:3,'');fori:=ltomdowrite(s[i]:6:1);writeln(ave:6:1);printlendend;Beginrrd(stu);print3(stu);readInend.程序臼定义Date记录类型,用来表示学生的出生年月日,含三个分量(称为域):day(日)为子界类型(1..31);mon(月)为子界类型(1..12);yea(年)为子界类型(1970.・1999);自定义Stuta记录类型,用来表示学生情况,含六个域:nu(学号)为字符类型(string[5]为5个字符);na(学号)为字符类型(string[8]为8个字符);dd(出生年月日)是前面所定义的date记录类型;se(性别)是char字符类型;s(表示学生成绩)是数组类型,各元素为real实型;ave(学生平均分)是real实型;程序定义的数组sarr的每个元素为Stuta记录(每个记录相当于ー张学生情况卡片,整个数组相当于全体学生的情况卡片)。自定义记录类型的一般格式为:访问记录中的分量,有两种方式:①T记录名.域名|例如对记录a中的nu赋值,可写成a.nu:=1008;{将1008赋给记录a中的分量nu}②["with记录名do语句]开域语句,with后面可同时打开多个记录,例如:witha,dddo语句;{a,dd都是记录名}
此文档下载收益归作者所有