Pascal教程(整理版)

文档属性

名称 Pascal教程(整理版)
格式 zip
文件大小 187.8KB
资源类型 教案
版本资源 通用版
科目 信息技术(信息科技)
更新时间 2008-12-01 11:15:00

图片预览

文档简介

TOC \o \h \z HYPERLINK \l "_Toc20129722" 第一章 简单程序 2
HYPERLINK \l "_Toc20129723" 第一节 Pascal 程序结构和基本语句 2
HYPERLINK \l "_Toc20129724" 第二节 顺序结构程序与基本数据类型 6
HYPERLINK \l "_Toc20129725" 第二章 分支程序 10
HYPERLINK \l "_Toc20129726" 第一节 条件语句与复合语句 10
HYPERLINK \l "_Toc20129727" 第二节 情况语句与算术标准函数 12
HYPERLINK \l "_Toc20129728" 第三章 循环程序 15
HYPERLINK \l "_Toc20129729" 第一节 for 循环 15
HYPERLINK \l "_Toc20129730" 第二节 repeat 循环 21
HYPERLINK \l "_Toc20129731" 第三节 While 循环 26
HYPERLINK \l "_Toc20129732" 第四章 函数与过程 31
HYPERLINK \l "_Toc20129733" 第一节 函数 31
HYPERLINK \l "_Toc20129734" 第二节 自定义过程 34
HYPERLINK \l "_Toc20129735" 第五章 Pascal的自定义数据类型 39
HYPERLINK \l "_Toc20129736" 第一节 数组与子界类型 39
HYPERLINK \l "_Toc20129737" 第二节 二维数组与枚举类型 47
HYPERLINK \l "_Toc20129738" 第三节 集合类型 55
HYPERLINK \l "_Toc20129739" 第四节 记录类型和文件类型 59
HYPERLINK \l "_Toc20129740" 第五节 指针类型与动态数据结构 66
HYPERLINK \l "_Toc20129741" 第六章 程序设计与基本算法 72
HYPERLINK \l "_Toc20129742" 第一节 递推与递归算法 72
HYPERLINK \l "_Toc20129743" 第二节 回溯算法 79
HYPERLINK \l "_Toc20129744" 第七章 数据结构及其应用 85
HYPERLINK \l "_Toc20129745" 第一节 线性表 85
HYPERLINK \l "_Toc20129746" 第二节 队列 89
HYPERLINK \l "_Toc20129747" 第三节 栈 92
HYPERLINK \l "_Toc20129748" 第四节 数组 96
HYPERLINK \l "_Toc20129749" 第八章 搜索 99
HYPERLINK \l "_Toc20129750" 第一节 深度优先搜索 99
HYPERLINK \l "_Toc20129751" 第二节 广度优先搜索 110
HYPERLINK \l "_Toc20129752" 第九章 其他常用知识和算法 114
HYPERLINK \l "_Toc20129753" 第一节 图论及其基本算法 114
HYPERLINK \l "_Toc20129754" 第二节 动态规划 121
第一章 简单程序
无论做任何事情,都要有一定的方式方法与处理步骤。计算机程序设计比日常生活中的事务处理更具有严谨性、规范性、可行性。为了使计算机有效地解决某些问题,须将处理步骤编排好,用计算机语言组成“序列”,让计算机自动识别并执行这个用计算机语言组成的“序列”,完成预定的任务。将处理问题的步骤编排好,用计算机语言组成序列,也就是常说的编写程序。在Pascal语言中,执行每条语句都是由计算机完成相应的操作。编写Pascal程序,是利用Pascal语句的功能来实现和达到预定的处理要求。“千里之行,始于足下”,我们从简单程序学起,逐步了解和掌握怎样编写程序。
第一节 Pascal 程序结构和基本语句
在未系统学习Pascal语言之前,暂且绕过那些繁琐的语法规则细节,通过下面的简单例题,可以速成掌握Pascal程序的基本组成和基本语句的用法,让初学者直接模仿学习编简单程序。
[例1.1]编程在屏幕上显示“Hello World!”。
Pascal程序:
Program ex11;
Begin
Writeln(‘Hello World!’);
ReadLn;
End.
这个简单样例程序,希望大家的程序设计学习能有一个良好的开端。程序中的Writeln是一个输出语句,它能命令计算机在屏幕上输出相应的内容,而紧跟Writeln语句后是一对圆括号,其中用单引号引起的部分将被原原本本地显示出来。
[例1.2]已知一辆自行车的售价是300元,请编程计算a辆自行车的总价是多少?
解:若总售价用m来表示,则这个问题可分为以下几步处理:
①从键盘输入自行车的数目a;
②用公式 m=300*a 计算总售价;
③输出计算结果。
Pascal程序:
Program Ex12; {程序首部}
Var a,m : integer; {说明部分}
Begin {语句部分}
Write(‘a=’);
ReadLn(a); {输入自行车数目}
M := 300*a; {计算总售价}
Writeln(‘M=’,m); {输出总售价}
ReadLn; {等待输入回车键}
End.
此题程序结构完整,从中可看出一个Pascal 程序由三部分组成:
(1)程序首部
由保留字Program开头,后面跟一个程序名(如:Exl1);其格式为:
Program 程序名;
程序名由用户自己取,它的第一个字符必须是英文字母,其后的字符只能是字母或数字和下划线组成,程序名中不能出现运算符、标点符和空格。
(2)说明部分
程序中所用的常量、变量,或类型、及过程与自定义函数,需在使用之前预先说明,定义数据的属性(类型)。[例1.2] 程序中 Var S,R,C: Real; 是变量说明,此处说明S,R,C三个变量均为实数类型变量。只有被说明为某一类型的变量,在程序中才能将与该变量同类型的数值赋给该变量。变量说明的格式为:
Var 变量表:类型;
(3)语句部分
指由保留字 Begin (开始)至 End. (结尾)之间的语句系列,是解决问题的具体处理步骤,也是程序的执行部分。
Pascal程序不管是哪部分,每句末尾都必须有分号(;),但允许最接近 End 的那个语句末尾的分号省略;程序结束的End末尾必须有圆点(. ),是整个程序的结束标志。
程序中花括号“{ }”之间的部分为注释部分。
Pascal程序结构可归纳用如下的示意图来表示:
Program 程序名; 程序首部
标号说明; (Label)
常量说明; (Const) 说明部分
类型说明; (Type)
变量说明; (Var)
过程或函数说明;
Begin 程序体 (主程序)
语句系列; 语句部分
End.
图1.1 Pascal程序的结构
把处理问题的步骤编成能从上到下顺序执行的程序,是简单程序的基本特征。再来分析下面两道例题的Pascal程序结构和继续学习基本语句。
[例1.3]编程计算半径为R的圆的面积和周长。
解:这是一个简单问题,按数学方法可分以下几步进行处理:
① 从键盘输入半径的值R; { 要求告诉圆的半径R }
② 用公式 S=πR2 计算圆面积;
③ 用公式 C=2πR 计算圆周长;
④ 输出计算结果。
Pascal程序:
Program Ex13; {程序首部 }
Var R,S,C: Real; {说明部分 }
Begin {语句部分 }
Write ('R= ');
Readln(R); {输入半径 }
S:=Pi*R*R; {圆面积公式S=πR2}
C:=2*Pi*R; {圆周长公式C=2πR}
Writeln('S=',S); {输出结果 }
Writeln('C=',C);
Readln {等待输入回车键}
End.
程序中Pi是Pascal提供的标准函数,它返回圆周率的近似值:3.1415926…。
(:=)是赋值符号,赋值语句的格式为:
变量:=表达式;
赋值语句的作用是将:=右边表达式的值记录到左边的变量中。
Writeln是输出语句,输出语句有三种格式:
① Write (输出项1,输出项2) ; {执行输出后光标不换行}
② Writeln (输出项1,输出项2) ; {执行输出后光标换到下一行}
③ Writeln {仅输出空白且光标换到下一行}
Writeln语句后面的圆括号以内部分均为输出项,可以是多项,各项间用逗号分隔; 对单引号里的内容按照引号内的原样(字符)输出显示。如果输出项是表达式,则只输出表达式的值,而不是表达式本身。
[例1.4] 输出两个自然数相除的商和余数。
解:设被除数、除数、商和余数,分别为A,B,C,D,均为变量,且都是整数类型。题中未给出具体的自然数A、B,可采用键盘输入方式。
① 给出提示,从键盘输入a, b;
② 显示两数相除的数学形式;
③ 求出a除以b的商c;
④ 求出a除以b的余数d;
⑤ 紧接等式后面输出显示商和余数。
Pascal程序:
Program Ex14;
Var a,b,c,d : integer;
Begin
Write('INPUT A,B:'); {给出提示信息}
Readln(a,b); {输入a,b}
Writeln; {输出一空行}
Write(a,'/',b,'='); {输出等式之后不换行}
c:=a div b; {整除运算,取商的整数部分}
d:=a mod b; {相除求余运算,取商的余数部分}
Writeln(C,'…',d); {输出后自动换行 }
Readln {等待输入回车键 }
End.
执行本程序中第一个Write语句,输出其引号以内的一串提示信息,是给紧接着的输入语句提供明确的提示(要求),有“一目了然,人机对话”之效果。
Readln是一个特殊的输入语句,要求输入一个回车(换行)才能往下执行。
Readln是输入语句,它的一般格式为:
① Read (变量1,变量2);
② Readln (变量1,变量2);
③ Readln
前两种格式均要从键盘给变量输入数据,输入时,所键入的数据之间以空格为分隔,以回车为输入结束。若多输入了数据(即数据个数超过变量个数),Read语句读完数据之后,能让后续的读语句接着读取多下来的数据;而Readln 语句对本行多输入的数据不能让后续语句接着读取多下来的数据。为了防止多输入的数据影响下一个输入语句读取数据,建议尽量使用Readln语句输入数据。第三种格式不需输入数据,只需按入一个回车键。
[例1.5]自然数的立方可以表示为两个整数的平方之差,比如43=102-62,请输出自然数1996的这种表示形式。(这里的43用自乘三次的形式4*4*4表示;102也用自乘二次的形式10*10表示)
解:此题没有现成的计算公式能直接利用,但可以自行推出处理方法或构建适当的运算公式,按着构想的处理方案编排出各步骤。
设这个自然数为N,两个平方数分别为X,Y, 将问题表示为求 N3=X2—Y2
① 先找出X的值,仔细观察题中的示例,用数学方法归纳可得出X=N*(N+1)/2;(构成本题可用的计算公式)
② 再仔细观察,发现Y值比X小一个N值,即 Y=X—N;
③ 输出等式 N3=X2—Y2 或N*N*N=X*X—Y*Y
Pascal程序:
Program Ex15;
Const N=1996; {常量说明 }
Var X,Y: Longint; {变量说明,此题计算中的数值较大,用长整型 }
Begin
X:=N*(N+1) div 2; { div 是整除运算 }
Y:=X-N;
Writeln(N,'*',N,'*', N,'=', X,'*', X,'—',Y,'*',Y); { 输出结果 }
Readln
End.
本程序中N是常量,X,Y是变量,为长整数类型(Longint); 程序中的div 是整除运算,其结果只取商的整数部分;
[例1.6] 求一元二次方程x2+3x+2=0的两个实数根。
解:方程的系数是常量,分别用a,b,c表示,可运用数学上现成的求根公式求方程的根,采取如下方法:
① 先求出d=b2-4ac;(求根公式中需用开方运算的那部分)
② 再用求根公式算出x1,x2的值。(x1,x2 = )
③ 输出x1,x2.
Pascal程序:
program Ex16;
Const a=1; {常量说明 }
b=3;
c=2; {a,b,c表示方程系数}
Var d : integer; {d为整型变量}
X1,X2: Real; {X1,X2为实型变量}
Begin
d:=b*b-4*a*c;
x1:=(-b+sqrt(d))/(2*a); {求方程的根}
x2:=(-b-sqrt(d))/(2*a);
Writeln('X1=',X1,'?':6,'X2=',X2);{输出结果}
Readln {等待输入一个回车键}
End.
本程序中的a,b,c均为常量;变量d是整数类型,而变量x1,x2则是实数类型,因为运算式中的Sqrt(d)开平方运算和(/)除法运算使结果为实数。Sqrt( ) 是开平方函数,是Pascal系统的一个标准函数。
习题1.1 模仿例题编程
1. 加法计算器:编程由键盘输入两个整数a和b,计算出它们的和并输出到屏幕上。
2. 某梯形的上底、下底和高分别为8,12,9,求该梯形的面积。
( 梯形面积公式为 S=
3. 求右图所示边长为5.6 的正立方体表面积。
4. 已知图园柱体的高为12,底面园的半径为7,求园柱体表面积。
5. 计算某次考试语文、数学、英语和计算机等四科的总成绩与平均成绩。
(请用输入语句从键盘输入各科成绩分)
第二节 顺序结构程序与基本数据类型
前面的简单程序已体现出处理问题步骤、思路的顺序关系,这就是顺序结构程序。
[例1.7]交换两个变量的值:由键盘输入两个正整数A和B,编程交换这两个变量的值。
解:交换两个变量的值,可以想象成交换两盒录音带(称为A和B)的内容,可以按以下步骤处理:
步骤①:拿一盒空白录音带C为过渡,先将A翻录至C;
步骤②:再将B翻录至A;
步骤③:最后将C翻录至B。
这样操作,可达到题目要求。
Pascal程序:
Program Exam17;
Var a,b,c : integer;
Begin
Write(‘A,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=8 B=8 C=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 就是三人原先的钱数 }
Pascal程序:
Program Exam18;
Var a,b,c: integer;
Begin
a:=8; b:=8; c:=8; {对应于步骤①}
a:=a div 2; b:=b div 2; c:=a+b+c; {对应于步骤②}
a:=a div 2; c:=c div 2; b:=a+b+c; {对应于步骤③}
b:=b div 2; c:=c div 2; a:=a+b+c; {对应于步骤④}
Writeln('a=',a,' ': 4,'b=',b,' ': 4,'c=',c) ;  {输出}
Readln
End.
细心观察,会发现本程序语句的顺序很关键。此例用反推顺序(逆序),按步骤正确推算出各变量的值。当然,有的问题可按正序步骤编程,这类程序都称为顺序程序。
本程序Writeln语句的输出项含有( ' ' : 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 {再用总头数减鸡数算出免的只数}
按此方法,这两步运算必须注意先后顺序才会符合运算逻辑。
Pascal程序:
Program Exam16;
Const H=30; {常量说明 }
F=90;
Var J,T: byte; {为字节类型的整数 }
Begin
J:=(4*H-F) div 2; {整除运算 }
T:=H-J
Writeln ('J=',J,' ': 6,'T= ',T ) ;
Readln
End.
本程序中H,F为常量,变量J,T为byte类型,属于整数类型。
Pascal定义了五个标准整数类型,如下表所示:
类型 取值范围 占字节数 格式
Shortint(短整型) -128..127 1 带符号8位
Integer (整型) -32768..32767 2 带符号16位
Longint(长整型) -2147483648..2147483647 4 带符号32位
Byte (字节型) 0..255 1 无符号8位
Word  (字型) 0..65535 2 无符号16位
在前面程序中常用的数据类型除整数类型,还有实数类型。Pascal 还定义了五个标准实数类型,列表所示如下:
类型 取值范围 占字节数 有效数字
Real 2.9×10-39~1.7×1038 6 7~8位
Single 1.5×10-45~3.4×1038 4 11~12位
Double 5.0×10-324~1.7×10308 8 15~16位
Extended 1.9×10-4951~1.1×104932 10 19~20位
Comp -263+1~238-1 8 19~20位
在Turbo Pascal 中实数的表示用科学记数法,可认为由三部分组成:
# . ## E +## 或 # . ## E -##
① #.##表示有效数字; ② E表示以10为底的幂; ③ +##或-##是指数部分,+号可省略。
例如: 1.7E+38 可写成1.7E38 (等同于1. 7×1038 )。
在实数类型定义下,即使是整数,在程序执行时系统也将自动转换成科学记数形式,试请运行下面程序并注意观察运行结果:
Program Exam17;
Var x: real; {x为实数类型 }
Begin
X:=180; {把整数180赋给实数类型变量X}
Writeln ('x=',x) ;     {输出的x自动表示成实数形式 }
Readln
End.
习题1. 2
1.已知△ABC中的三边长分别为25.76,74.03,59.31,求△ABC的面积。
( 计算公式: S= 。 其中P = )
2.某车棚存有自行车和三轮车共65辆,它们的轮子数合计为150个。求该棚内存有的自行车和三轮车各是多少辆?
3.甲、乙、丙三人分别有磁带36,48,64盒。先由甲把自己的磁带平均分为三份,分给乙、丙各一份,自己留下一份;接着是乙,最后是丙,都按甲的方法处理。编程输出甲、乙、丙在上述过程中各人的磁带数分别是多少 (输出所有的中间结果)
4.五位好朋友相聚。第一位朋友带来了很多糖块赠送给各位朋友,使每人的糖块在各自原有的基础上翻了一倍;接着第二位好友也同样向每人赠送糖块,他同样使每人的糖块在各人已有的数量上翻了一倍;第三、第四、第五位好友都照此办理。经过这样的赠送之后,每人的糖块恰好都为32块。问各位好友原先的糖块数分别是多少
第二章 分支程序
在程序设计中,许多问题是在一定条件下才选择某种处理方式的,这就需要用条件判断语句或情况选择语句进行处理。程序执行中将出现选择(分支),根据条件只选择执行部分语句,不一定都是按原顺序从头到尾地执行所有语句,这样的程序称为分支程序。
第一节 条件语句与复合语句
[例2.1] 某服装公司为了推销产品,采取这样的批发销售方案:凡订购超过100 套的,每套定价为50元,否则每套价格为80元。编程由键盘输入订购套数,输出应付款的金额数。
解:设X为订购套数,Y为付款金额,则:
① 输入X;
② 判断 X 值;
③ 根据判断结果选择符合条件的那种方法计算Y值;
④ 输出计算结果。
Pascal程序:
Program Exam21;
Var x,y: integer;
Begin
Write('X=') ;Readln(x) ; { 输入X}
if x >100 then y:=50*X else y:=80*X; {条件判断与选择 }
Writeln('y=',y) ;
Readln
End.
程序中的 if 语句常称为条件语句,它的一般格式为:
(1) if 条件 then 语句;
(2) if 条件 then 语句1 else 语句2;
IF 语句的功能是按条件在两种可能中选择其中一种。习惯上把if 后面的表达式称为条件,then 后面的语句称为真项,else 后面的语句称为假项。若条件成立(为真)就执行真项,然后执行if语句的后继语句;若条件不成立(为假)就跳过真项而执行假项,然后执行后继语句。而第一种格式只有真项,没有假项,当条件不成立(为假)就什么也不需做,直接往下去执行后继语句。
[例2.2] 读入三个不同的数,编程按由小到大的顺序排列打印出来。
解:设读入的三个数为a,b,c,为了把较小的数排在前面,可作如下处理:
① 如果a>b就交换a、b的值,将较大的值换至后面;
② 如果a>c就交换a、c的值,将较大的值换至后面;
③ 如果b>c就交换b、c的值,将较大的值换至后面;
④ 输出处理后的a,b,c。
Pascal程序:
Progranm Exam22;
Var a,b,c,t: Real;
Begin
Write('Input a, b,c=');
Readln(a,b,c);
if a>b then
begin {复合语句}
t:=a; a:=b; b:=t {交换a,b}
end;
if a>c then
begin {复合语句}
t:=a; a:=c; c:=t {交换a,c}
end;
if b>c then
begin {复合语句}
t:=b; b:=c; c:=t {交换b,c}
end;
Writeln('a,b,c:',a:6, b:6, c:6);
Readln
End.
if 语句规定它的真项或假项位置上只能是一个基本语句,如果需要写一组语句,就应当使用复合语句。本程序中有三处用到复合语句。每个复合语句的范围是从Begin开始到与它相对应的End为止。复合语句的地位和一个基本语句相同;其一般格式为:
Begin
语句系列
End;
习题2. 1
1.假设邮局规定寄邮件时若每件重量在1公斤以内(含1公斤),按每公斤1.5元计算邮费,如果超过1公斤时,其超出部分每公斤加收0.8元。请编程序计算邮件收费。
2.输入三个正整数,若能用这三个数作为边长组成三角形,就计算并输出该三角形的面积,否则输出Can't。(组成三角形的条件为:任意两边之和大于第三边)
3.输入一个三位数的整数,将数字位置重新排列,组成一个尽可大的三位数。例如:输入213,重新排列可得到尽可能大的三位数是321。
第二节 情况语句与算术标准函数
如果有多种(两种或两种以上)选择,常用情况语句编程。
将前面[例2.1]改成用如下方法来处理。根据题意,付款计算可分为两种情况:
① Y=50*X (X>100)
② Y=80*X (X<=100)
显然,情况①与②的选择取决于X值。假设用N表示“情况值”,暂且先让N=2;
如果X>100则N=1;(此题中N的值只是1或2,且取决于X值)
Pascal 程序:
Program Exam21_1;
Var X,Y,N: integer;
Begin
Write('X=') ;readln(x) ; n:=2; { 先让n=2 }
if X>100 then n:=1; {如果X>100则 n=1 }
Case n of { 关于情况处理 }
1: Y:=50*X;
2: Y:=80*X;
end;
Writeln('Y=',Y) ;
Readln
End.
程序中的 Case─end 语句为情况语句,是多路分支控制,一般格式为:
Case 表达式 of
情况常量表1: 语句1;
情况常量表2: 语句2;
: :
情况常量表n: 语句n
end;
执行情况语句时,先计算Case后面表达式的值,然后根据该值在情况常量表中的“对应安排”,选择其对应的语句执行,执行完所选择语句后就结束Case语句;如果常量表中没有一个与表达式值对应的语句,则什么也不做就结束本Case语句。
Case 语句的另一种应用格式为:
Case 表达式 of
情况常量表1: 语句1;
情况常量表2: 语句2;
: :
情况常量表n: 语句n;
else 语句 n+1
end;
这种格式的前面部分是相同的,所不同的是:如果常量表中没有一个与表达式值对应的语句,则执行与else对应的语句,然后结束Case语句。
[例2.2] 对某产品征收税金,在产值1万元以上征收税5%;在1万元以下但在5000元
以上的征收税3%;在5000元以下但在1000元以上征收税2%;1000元以下的免收税。编程计算该产品的收税金额。
解:设x为产值,tax为税金,用P表示情况常量各值,以题意中每1000元为情况分界:
P=0: tax=0 (x<1000 )
P=1,2,3,4: tax=x*0.02 (1000<=x<5000 )
P=5,6,7,8,9: tax=x*0.03 (5000P=10: tax=x*0.05 (x> 10000 )
这里的P是“情况”值,用产值x除以1000的整数值作为P,如果P>10也归入P=10的情况。Pascal语言用P=trunc(x/1000)取整计算,
Pascal程序:
Program Exam22;
Var x,p : integer;
Tax : real;
Begin
Write('Number=') ; readln(x) ;
P:=trunc(x/1000) ;
if P>9 then P:=10;
Case P of
0 : tax:=0;
1,2,3,4 : tax:=x*0.2;
5,6,7,8,9 : tax:=x*0.3;
10 : tax:=x*0.5
end;
Writeln('tt=',tt:5:2) ;
Readln
End.
情况表达式的计算必须考虑到“全部”情况,不要有遗漏。如果情况常量表的“值”在某范围内是连续的,可将常量表写成:
n1.. n2:语句;
因此,上面程序中的情况常量表可以写成如下程序中表示形式:
Program Exam22_1;
Var x,p: integer;
tax: real;
Begin
Write('Number=') ; readln(x) ;
P:=trunc(x/1000) ;
if P>9 then P:=10;
Case P of
0 : tax:=0;
1..4 : tax:=x*0.2; { 从1至4作为同一情况处理 }
5..9 : tax:=x*0.3; { 从5至9作为同一情况处理 }
10 : tax:=x*0.5
end;
Writeln('tt=',tt:5:2) ;
Readln
End.
程序中的trunc(x)为取整函数,是Pascal的算术标准函数之一。Pascal常用的算术标准函数有19个:
(1) abs(x) 求x的绝对值(|x|);
(2) exp(x) 求ex的值; (e为无理数2.71828…)
(3) frac(x)求x的小数部分;
(4) int(x) 求x的整数部分(不舍入,函数值为实型);
(5) ln(x) 求以e为底的x的对数(log ex );
(6) odd(x) 判断x的奇偶数(当x为奇数时odd(x)值为true,否则为false);
(7) ord(x) 求x的序号,结果为整型(x为有序类型量);
(8) pi π值(3.1415926535897932…);
(9) pred (x) 求x(有序类型)的前趋值;
(10) succ(x) 求x(有序类型)的后继值;
(11) random 随机函数,产生0~1的随机值;
(12) random(n)产生0~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.2
1.运输公司计算运费时,距离(S)越长,每公里运费越低,标准如下:
如果S<250公里;运费为标准运价的100%
如果250公里<=S<500公里,运费为标准运价的98%;
如果500公里<=S<1000公里,运费为标准运价的95%;
如果1000公里<=S<2000公里,运费为标准运价的92%;
如果2000公里<=S<3000公里,运费为标准运价的90%;
如果S=>3000公里,运费为标准运价的85%;。请编计算运费的程序。
2. 输入考试成绩,如果获85分以上为 A等,获60分~84分为B等,60分以下为C等,编程输出考试等级。
3. 某车间按工人加工零件的数量发放奖金,奖金分为五个等级:每月加工零件数N < 100者奖金为10元;100 < = N < 110者奖金为30元;110 < = N <120 者奖金为50元;120 < = N <130 者奖金为70元;N > 130者为80元。
请编程,由键盘输入加工零件数量,显示应发奖金数。
第三章 循环程序
在编程中经常遇到需要多次规律相同的重复处理,这就是循环问题。Turbo Pascal采用不同的循环方式来实现,常用的环循有三种: for、repeat、while.
第一节 for 循环
for循环是一种自动计数型循环。
[例3.1] 试打印出1~20的自然数。
解:① 用a代表1~20各数,同时也用a兼作计数,以控制循环次数;
② 让a从1开始;
③ 输出a;
④ a自动计数(加1),如果未超越所规定的循环范围则重复步骤③,否则结束循环。
Pascal程序:
Program Exam12;
Var a: byte;
Begin
for a:=1 to 20 do
Writeln (a);
Readln
End.
程序中 for a:=1 to 20 do Writeln (a); 是for循环语句。
for 循环语句有两种格式:
(1) for 循环变量:=初值 To 终值 do 语句;
(2) for 循环变量:=初值 downto 终值 do 语句;
第(1)种格式的初值小于等于终值,循环变量值按自动加1递增变化;
第(2)种格式的初值大于或等于终值,循环变量值按自动减1递减变化。for 循环是 (以递增1或以递减1) 计数型循环。
比如: 若将[例3.1]程序改为倒计数(递减)循环,则输出20~1的自然数数:
Program Exam31;
Var a: byte;
Begin
for a:=20 downto 1 do
Writeln(a) ;
Readln
End.
[例3.2]打印出30至60的偶数。]
解:
方法一:
①设a表示30至60的所有的数,可用for循环列出;
②用式子 a mod 2=0 筛选出其中的偶数并输出。
Pascal程序:
Program ex32;
Var a : integer;
Begin
For a := 30 to 60 do
If (a mod 2=0) then writeln(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 求出其中的偶数;
③将结果输出至屏幕。
Pascal程序:
Program ex32;
Begin
For n := 15 to 30 do
Begin
a := 2*n;
Writeln(a);
End;
Readln;
End.
[例3.3]自然数求和:编一个程序,求从1至100的自然数的和。
解:① 令S=0;
② 令a表示1至100的自然数,用循环列出;
③ 将这些自然数用公式S:=S+a 逐一累加到S中去;
④ 循环结束后,S即为1至100的自然数的和,输出即可。
Pascal程序:
Program ex33;
var s,a : integer;
Begin
S := 0;
For a := 1 to 100 do
S := S+a;
Writeln(‘S=’,S);
Readln;
End.
[例3.4]一个两位数x,将它的个位数字与十位数字对调后得到一个新数y,此时y恰好比x大36,请编程求出所有这样的两位数。
解:① 用for循环列举出所有的两位数,x为循环变量;
② 用公式a:= x div 10分离出x的十位数字;
③ 用公式b:= x mod 10分离出x的个位数字;
④ 用公式y:= b*10+a合成新数y;
⑤ 用式子y-x=36筛选出符合条件的数x并输出。
Pascal程序:
Program ex34;
Begin
For x := 10 to 99 do
Begin
a := x div 10;
b := x mod 10;
y := b*10+a;
if y-x=36 then writeln(x);
End;
Readln;
End.
[例3.5] 把整数3025从中剪开分为30和25两个数,此时再将这两数之和平方,(30+25)2=3025计算结果又等于原数。求所有符合这样条件的四位数。
解:设符合条件的四位数为N,它应当是一个完全平方数,用(a*a)表示。
① 为了确保N=(a*a)在四位数(1000~9999)范围内,可确定a在32~99循环;
② 计算N=a*a;将四位数N拆分为两个数n1和n2;
③ 若满足条件(n1+n2)*(n1+n2)=N 就输出 N 。
Pascal程序:
Program Exam35;
Var N,a, x,n1,n2: Integer;
Begin
for a:=32 to 99 do
begin
N:=a*a;
n1:= N div 100; {拆取四位数的前两位数}
n2:= N-n1*100; {拆取四位数的后两位数}
X:=n1+n2;
if x*x=N then writeln (N);
end;
Readln
End.
[例3.6]用“*”号打印出如下的长方形图案。
  *********
*********
*********
*********
解:① 上面给出的图例共有4行,我们可以用一个循环控制行的变化;
② 在每行中又有9列,我们可以在前面控制行的循环中再套一个循环来控制列的变化。
Pascal程序:
Program ex36;
Begin
For a := 1 to 4 do {外循环控制行的变化}
Begin
For b := 1 to 9 do {内循环控制列的变化}
write(‘*’);
Writeln; {输出一行的“*”后换行}
End;
Readln;
End.
程序中的循环对于a的每个值都包含着一个b=(1~9)次的内循环。外循环for a 将内循环for b 包含在里面,称为for循环的嵌套。嵌套形式如:
for a:=n1 to n2 do
for b:=m1 to m2 do 循环体语句;
[例3.7] 打印出九九乘法表:
解:设a为被乘数,范围为1~9;b为乘数,范围为1~a;乘式为a*b=(a,b的乘积),则
a=1: b=1~a 1*1=1
a=2: b=1~a 2*1=2 2*2=4
a=3: b=1~a 3*1=3 3*2=6 3*3=9
a=4: b=1~a 4*1=4 4*2=8 4*3=13 4*4=16
: :
a=9 b=1~a 9*1=9 9*2=18 … 9*9=81
⑴从上面分解的横行中看到共有9行,这里的“行”数变化与a的变化从1~9相同,可用a控制“行”的循环;
⑵每“行”里面相乘的次数与b的范围相关,由b控制每“行”里面的“内部”循环;
⑶内循环被包含在最里层,执行完每“行”的内部循环,就到下一“行”去执行新“行”里面的循环,每“行”都拥有形式相同的( b=1~a )内循环。
即每到一“行”都要执行该“行”的内循环。这里所指的“行”可以理解成抽象的行,不一定是实际上具体对应的行,可以是一个处理“块”。
Pascal程序:
Program Exam37;
Var a,b: byte;
Begin
for a:=1 to 9 do {外循环 }
begin
for b:=1 to a do {内循环 }
write(a,’* ’,b,’= ’,a*b,’ ’:3);
writeln
end;
Readln
End.
根据这种格式还可以实现多层循环嵌套,例如:
for a:=n1 to n2 do
for b:=m1 to m2 do
for c:=k1 to k2 do 循环体语句;
[例3.8]从七张扑克牌中任取三张,有几种组合方法?请编程输出所有组合形式。
解:设每次取出三张分别为a,b,c。用三重循环分别从1~7的范围里取值;为了排除取到重号,用(a-b)*(b-c)*(a-c) < >0进行判断。
Pascal程序:
program Exam38;
const n=7;
var a,b,c,t: integer;
Begin
t:=0;
for a:=1 to n do
for b:=1 to n do
for c:=1 to n do
if (a-b) * (b-c) * (a-c) < >0 then
Begin
inc (t);
writeln (a:3, b:3, c:3)
End;
writeln ( total:, t :5);
readln
End.
[例3.9] 数学上把除了1和它本身,没有别的数能够整除它的自然数叫做素数(或质数)。现在由键盘输入一个自然数N,编程判断N是否是素数,是则输出“Yes”,否则输出“No”。
解:根据定义,对于给定的自然数N,只需判断除1和它本身外,还有没有第三个自然数即可。
① 令K从1循环至N;
② 根据N mod K是否为0可统计K的约数的个数;
③ 若N的约数的个数超过2个,则判定N不是素数。
Pascal程序:
Program Exam39;
Var n,m,k,t: integer;
Begin
write(‘N=’);
ReadLn(N);
t:=0;
for k:=1 to N do {外循环 }
if N mod k=0 then t := t+1; {如果N是奇数 }
if t>2 then writeln(‘No’)
else writeln(‘Yes’);
Readln;
End.
程序中的变量yse为布尔(或逻辑)类型(Boolean)。布尔值只有两个:
True(真) False(假)
布尔值与条件判断结果为真(条件成立)或为假(条件不成立)的作用相同,常用于条件语句和循环语句中。
上面程序中用 if yes and (t mod 7=0) then writeln;实现每行打印七个素数换行,程序中布尔变量yes为真,在逻辑上表示是素数;关系式(t mod 7=0) 的值为真时,表示该行输出素数巳是7个;用and将这两个“条件”连起来是作一种布尔(逻辑)运算。
Pascal 共有四种逻辑运算符:
① 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循环程序完成)
4.一辆快车和一辆慢车开往同一地点,快车票价为18元,慢车票价为13. 5元,共售出400张,共计5940元,求快车票和慢车票各多少张 .
5.求出能被5整除的所有四位数的和。
6.在下面式子中的二个□内填入一个合适的同样的数字,使等式成立。
□3*6528=3□*8256
7.有一个三位数,它的各位数字之和的11倍恰好等于它自身,请编程求出这个三位数。
8.在自然数中,如果一个三位数等于自身各位数字之立方和,则这个三位数就称为是水仙花数。如:153=13+53+33,所以153是一个水仙花数。求所有的水仙花数。
9.编程序打印出下列图案:
平行四边形 等腰三解形      菱形
  ****** *   *
****** *** ***
****** ***** *****
****** ******* ***
****** ********* *
10.编程打印出如下图案:
1
222
33333
4444444
555555555
11.有三种明信片:第一种每套一张,售价2元;第二种每套一张,售价4元; 第三种每套9张,售价2元。现用100元钱要买100张明信片,要求每种明信片至少要买一套,问三种明信片应各买几套?请输出全部购买方案。
12.某人想把一元钱换成伍分、贰分、壹分这样的零钱, 在这三种零钱中每种零钱都至少各有一个的情况下,共有多少种兑换方案。并打出这些方案。
14. 输出100 以内的全部素数,要求每行显示5 个。
15.A、B两个自然数的和、差、积、商四个数加起来等于243,求A、B两数。
16.百钱买百鸡:今有钱100元,要买100只鸡,公鸡3元一只,母鸡1元一只,小鸡1元3只,若公鸡、母鸡和小鸡都至少要买1只,请编程求出恰好用完100元钱的所有的买鸡方案。
第二节 repeat 循环
Repeat循环是直到型循环。
试将上一节的例3.1(打印出1~20的平方数表)程序改为 repeat 循环:
Program Exam31_1;
Var a: byte;
Begin
a:=1; writeln ( ' a ' : 8 , ' a*a ' : 8 ) ;
repeat
writeln ( a :8,a*a : 8);
inc(a); {改变a的值 }
Until a>20;
Readln
End.
程序中的Repeat循环格式为:
repeat
循环体语句;
until 条件表达式; {直到条件为真}
Repeat循环首先执行由Repeat和Until括起来的循环体语句,然后检查Until后面的条件表达式:如果表达式结果为假,则继续执行循环体,接着继续检查Until后面的条件表达式,如此反复执行直到这个表达式结果为真时结束循环。Repeat循环体语句必须有能改变Until后面条件表达式值的语句,并最终使这个条件表达式的值为真,使循环自动结束。
程序中inc (a) 指令相当于a : =a+1,常用的同类指令格式如下:
(1) inc(x) 等同 x:=x+1;
(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)向下寻找,找到的第一个公约数即是最大公约数。
Pascal程序:
Program ex310;
Begin
a := N+1;
Repeat
a := a-1;
Until (M mod a=0) and (N mod a=0);
writeln(a);
Readln;
End.
[例3.11]校体操队到操场集合,排成每行2人,最后多出1人;排成每行3人,也多出1人;分别按每行排4,5,6人,都多出1人;当排成每行7人时,正好不多。求校体操队至少是多少人
解:①设校体操队为X人,根据题意X应是7的倍数,因此X的初值为7,以后用inc(x,7)改变X值;
②为了控制循环, 用逻辑变量yes为真(True) 使循环结束;
③如果诸条件中有一个不满足, yes 的值就会为假(false),就继续循环。
Pascal程序:
program Exam311;
var x: word; yes : boolean;
begin
x:=0;
repeat
yes :=true; inc(x,7);
if x mod 2 < > 1 then yes:=false;
if x mod 3 < > 1 then yes:=false;
if x mod 4 < > 1 then yes:=false;
if x mod 5 < > 1 then yes:=false;
if x mod 6 < > 1 then yes:=false;
until yes; {直到yes的值为真 }
writeln('All =', x) ; readln
end.
程序中对每个X值,都先给Yes 赋真值,只有在循环体各句对X进行判断时,都得到“通过”(此处不赋假值)才能保持真值。
[例3.12]从键盘输入一个整数X(X不超过10000),若X的各位数字之和为7的倍数,则打印“Yes”,否则中打印“No”。
解:本题考察的是数字分离的方法,由于X的位数不定,所以以往的解法不能奏效,这是介绍一种取余求商法。
(1)用X mod 10分离出X的个位数字;
(2)用X div 10将刚分离的个数数字删除,并将结果送回给X;
(3)重复(1)(2)直到X=0。
Pascal程序:
Program ex12;
var x,a,s : integer;
begin
s := 0;
repeat
a := x mod 10;
x := x div 10;
s := s+a;
until x=0;
if s mod 7=0 then writeln(‘Yes’)
else writeln(‘No’);
Readln;
end;
[例3.13]求1992个1992的乘积的末两位数是多少?
解:积的个位与十位数只与被乘数与乘数的个位与十位数字有关,所以本题相当于求1992个92相乘,而且本次的乘积为下一次相乘的被乘数,因此也只需取末两位参与运算就可以了。
Pascal程序:
Program ex313;
var a,t : integer;
Begin
a := 1;
t := 0;
repeat
t := t+1;
a := (a*92) mod 100;
until t=1992;
writeln(a);
Readln;
End.
[例3.14]尼科彻斯定理:将任何一个正整数的立方写成一组相邻奇数之和。
如: 33=7+9+11=27 43=13+15+17+19=64
解:从举例中发现:
(1) n3正好等于n个奇数之和;
(2) n个奇数中的最小奇数是从1开始的奇数序列中的第m个奇数,与 n 的关系为: m=n (n —1) / 2+1。
(3) 奇数序列中第m个奇数的值为x,且 x= 2m—1,比如: n=3时,m=3(3-1)/2+1=4,即3个奇数中最小的奇数是奇数序列中的第4个,它的值为x=(2m-1)=7, 所以:33=7+9+11。
(4) 从最小的奇数值x开始,逐个递增2,连续n个,用t从1开始计数,直到t=n为止。
Pascal程序:
Program Exam35;
Var n,m,x,t,s : integer;
Begin
write(’input n:’); readln(n); {输入N }
m:=(n*(n-1) div 2)+1; {找到第m个奇数 }
x:=2*m-1; t:=1; {算出第m个奇数的值x,是所求的第一个}
write(n’*’,n,’*’,n,’=’,x);{输出第一个}
s:=x; {用S计算和 }
if n>1 then
Repeat
inc(x,2); { 计算下一个奇数 }
write (’+ ’,x) ; {加上下一个奇数 }
inc (t ); inc (s,x); { 计个数并累加和 }
Until t=n; {直到n个 }
Writeln (’= ’,s ) ;
Readln
End.
[例3.15]猜价格:中央电视台的“幸运52”栏目深受观众喜爱,其中的“猜商品价格”的节目更是脍炙人口,现在请你编一个程序模拟这一游戏:由计算机随机产生200至5000之间的一个整数,作为某件商品的价格,然后由你去猜是多少,若你猜的数大了,则计算机输出提示“Gao”,若你猜的数小了,则计算机输出提示“Di”,然后你根据提示继续猜,直到你猜对了,计算机会提示“Ok”,并统计你猜的总次数。
解:本题的游戏规则大家都清楚,要完成程序,必须把处理步骤理清:
  (1)用随机函数Random产生200至5000之间的一个整数X;
(2)你猜一个数A;
(3)若A>X,则输出“Gao”;
(4)若A<X,则输出“Di”;
(5)若A=X则输出“Ok”;
(6)重复(2)(3)(4)(5)直到A=X。
Pascal程序:
Program ex315;
Var t,X,a : integer;
Begin
Randomize;
X := Random(4800)+200;
t := 0;
Repeat
t := t+1;
write(‘[‘,t,’] Qing cai yi ge zheng shu : ‘);
readln(a);
if a>x then writeln(‘Gao’);
if aif a=x then writeln(‘Ok’);
Until A=X;
Readln;
End.
习题3.2
1.求两个自然数M和N的最小公倍数。(如果求三个或更多个数的最小公倍数呢?应如何解决)
2.小会议室里有几条相同的长凳,有若干人参加开会。如果每条凳子坐6人,结果有一条凳子只坐有3人;如果每条凳子坐5人,就有4人不得不站着。求会议室里有多少人开会,有多少条长凳
3.某动物饲养中心用1700元专款购买小狗(每只31元)和小猫(每只21元)两种小动物。要求专款专用,正好用完, 应当如何购买 请输出所有方案。
4.某整数X加上100就成为一个完全平方数,如果让X加上168 就成为另一个完全平方数。求X
5.某次同学聚会,老同学见面个个喜气洋洋,互相握手问好。参加此次聚会者每人都与老同学握了一次手,共握903次,试求参加聚会的人数?
6.用自然数300,262,205,167分别除以某整数A,所得到的余数均相同。求出整数A以及相除的余数?
7.1600年前我国的一部经典数学著作中有题:“今有物,不知其数,三三数之,剩二;五五数之,剩三;七七数之,剩二,问物几何。”求最小解。
8.编程求出所有不超过1000的数中,含有数字3的自然数,并统计总数。
9.阿姆斯特朗数:如果一个正整数等于其各个数字的立方和,则该数称为阿姆斯特朗数(也称自恋数),如407=43+03+73,试编程求出1000以内的所有阿姆斯特朗数。
第三节 While 循环
While循环是当型循环。
[例3.8] 前面第一章[例1.2]的鸡兔同笼,头30,脚90, 求鸡兔各几只?在此用下面方法编程求解。
解: 设鸡为J只,兔为T只。已知头为H, 脚为F。
  ①让鸡的只数逐次加1进行递推计算,初始时J=0;
②计算兔的只数T=H-J;
③当总脚数(4*T+2*J) < > F就做 (J=J+1,T=H-J);
④当4*T+2*J=F时,说明所推算的J和T是正确的,应结束循环,并输出T, J。
Pascal程序:
Program Exam38;
Const H=30;
F=90;
Var J,T : integer;
Begin
J:=0; T:=H-J; {初始时让J从0开始计算 }
While 4*T+2*J<>F do {当条件为真就做do后面的循环体 }
begin
inc(J);    { 递推改变J值 }
T:=H-J   {计算兔的只数 }
end;
Writeln('T=',T,' ':6, 'J=', J ) ;
Readln
End.
程序中采用While当型循环,While循环语句的格式为:
While 条件式 do 语句;
其中do后面的“语句”是被重复执行的,称为循环体;若循环体是多个语句, 必须用begin--end包起来成为复合语句。
While循环首先判断条件式,当条件式的值为真就执行do 后面的语句(循环体)。
While的循环体内也必须包含能改变控制变量取值语句, 影响条件式的值, 最终使条件式为false (假), 才能结束循环。
[例3.9] 输入任一的自然数A, B, 求A , B的最小公倍数。
解:这里采用适合计算机查找的方法: 设D是它们的最小公倍数。先找出A, B当中的较大者并存放在A中, 将较小者存放在B中, 让D=A, 当D能够整除B时, 则D是所求的最小公倍数;当D不能整除B,就逐次地让D增加A。例如:A=18, B=12, 步骤如下:
① 让D=A (D=18)
② 当(D mod B)<>0 为真时 ( D不能整除B ) 就做 D=D+A, 重复②;
③ 当(D mod B)<>0 为假时结束循环,并输出D。
Pascal程序:
program Exam39;
var a,b,d,t : word;
begin
write('input a,b: '); readln(a , b);
if abegin
t:=a; a:=b; b:=t
end;
d:=a;
while d mod b < >0 do {当条件为真时就做do后面的语句 }
inc(d,a);
writeln('[', a, ' , ' , b, ']=', d) ;
readln
End.
Pascal语言的三种基本循环方式, for循环对循环范围有明确规定, 且循环变量只能是递增加1或递减1自动计数控制; 而repeat--until循环和while--do循环比较灵活, 只要对条件表达式的值能控制满足一定要求就能组成循环, 但在循环体中必须有改变循环变量值的语句, 使条件判断(逻辑值)最终为True或flase, 让循环能够终止。
[例3.10]求自然数A, B的最大公约数。
解:采用如下方法步骤:
(1)求A除以B的余数;
(2)当余数<>0就做n=a; a=b; b=n mod b, 重复(1)和(2);
(3)当余数=0就结束循环,并输出b值。
比如a=18, b=12时,处理步骤为:
(1) a mod b = 6 ,得余数为6;
(2) 此余数不为零 ,让a = 12, b = 6;
(3) 重复 a mod b = 0 , 得余数为0;
(4) 结束循环,输出6(余数为零时的b值即是所求的最大公约数)。
此方法称为辗转相除法求最大公约数。
Pascal程序:
program Exam310;
var a,b, n : word;
begin
write('input a,b: '); readln (a,b);
write('(', a, ' , ' , b, ')=' ) ;
while a mod b < > 0 do
begin
n:=a; a:=b; b:=n mod b;
end;
writeln(b);
readln
End.
[例3.11]将一根长为369cm的钢管截成长为69cm和39cm两种规格的短料。在这两种规格的短料至少各截一根的前提下, 如何截才能余料最少。
解:设两种规格的短料分别为:
规格为69cm的x根,可在1至(369-39)/69范围循环取值;
规格为39cm的y根,用y = (369-69*X)/39)计算;
余料R=369-69*X-39*Y。
①设最小余料的初始值min=369;
②在X循环范围内,每一个X值都计算出对应的Y和R;
③如果R<min, 就将R存入min, x存入n, y存入m,记录余料最小时的x和y ;
④重复步骤②,当x值超出 ((369—39)/ 69) 时结束循环。
Pascal程序:
program exam311;
var x,y,r,min,n,m,a: integer;
begin
min:=369;
a:=(369-39) div 69; x:=1;
while x<=a do
begin
y:=(369-69*x) div 39;
r:=369-69*x-39*y;
if rbegin
min:=r; n:=x; m:=y
end;
inc(x);
end;
writeln('min=', min, ' x=', n, ' y=', m) ;
readln
end.
在有些情况中, 三种循环方法可以互相换用。
[例3.12]甲、乙、丙三人都是业余射击爱好者, 在一次练习中他们枪枪中靶: 甲射了八发子弹,取得225环成绩,乙射了七发,也取得225环;丙只射了六发,同样取得225环。下面是成绩表,请编程完成下表中空项的填数。
射子弹数 中50环有几发 中35环有几发 中25环有几发 成绩(环)
甲 8 225
乙 7 225
丙 6 225
解:①设N为发射子弹数, 只有8, 7, 6三个数字, 正好又可用来代表甲、乙、丙;
②设A为中50环的子弹数, 最小为0, 最大为(225 div 50=4);
B为中35环的子弹数, 最小为0, 最大为(225 div 35=6);
C为中25环的子弹数, C=N-A-B, 但必须C>0才可能正确;
③先让N=8, A取值(0~4), B取值 (0~6)用循环逐个选定, 在C>0的情况下若能满足条件A*50+B*35+C*25=225就能确定一组填数。然后选N的下一数值,重复同样的过程。
Pascal程序:
program exam312;
var a,b,c,n,s : integer;
begin
writeln('n':3, 'a':3, 'b':3, 'c':3, 's':5) ;
n:=8;
while n>=6 do
begin
a:=0;
while a < = 4 do
begin
b:=0;
while b < = 6 do
begin
c:=n-a-b;
if c>0 then
begin
s:=50*a+35*b+25*c;
if s=225 then writeln(n:3,a:3,b:3,c:3,s:5);
end;
inc(b);
end;
inc(a);
end;
dec(n);
end;
readln
end.
程序运行结果获得两组填数答案。如果改用for循环,程序将更加简明:
Program Exam312_1;
Var a,b,c,n,s : Integer;
Begin
Writeln('N':3, 'A':3, 'B':3, 'C':3, 'S':5) ;
for n:=8 downto 6 do {N取值8,7,6,并分别代表甲、乙、丙 }
for a:=0 to 4 do {中50环的可能范围 }
for b:=0 to 6 do {中30环的可能范围 }
begin
c:=n-a-b; { 计算中25环的子弹数 }
if c>0 then begin {如果不是负数 }
s:=50*a+35*6+25*c; {计算总成绩 }
if s=225 then writeln(n:3,a:3,b:3,c:3,s:5);
end
end;
readln
End.
习题3.3
1.求S= 1-1/2 +1/3-1/4+1/5-1/6+ ……(求前N项的和)
2. Faibonacci数列前几项为: 0,1,1,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.请编程显示出下面数字金字塔图形:
第四章 函数与过程
程序中往往需要把主要任务分成若干个子任务,每个子任务只负责一个专门的基本工作。每个子任务就是一个独立的子程序。Turbo Pascal 可以把函数和过程作为子程序调用。
第一节 函数
Pascal允许用户在程序中自己说明定义所需要的函数并在程序中调用这些函数。
[例4.1]编程找出由键盘任意输入五个整数中的最大整数。
解:设输入的五个整数为n1、n2、n3、n4、n5,为了便于处理,引入一个中间变量t1,按如下步骤处理:
①令t1=n1;
②将t1与n2比较,将两者中较大的数放入t1;
③将t1与n3比较,将两者中较大的数放入t1;
④将t1与n4比较,将两者中较大的数放入t1;
⑤将t1与n5比较,将两者中较大的数放入t1;
⑥经过以上5步处理后,t1即为5个数中最大者。
从上面规划的步骤看来,从步骤②到步骤⑤需处理的目标是相同的,因此我们可以设计一段子程序Max(x1,x2),以找出x1和x2中最大的值并返回。
Pascal程序:
Program Exam41_a;
Var n1,n2,n3,n4,n5,t1 : integer;
Function max(x1,x2 : integer) : integer;
Begin
If x1>x2 then Max := x1
Else Max := x2;
End;
Begin
Write(‘Input 5 numbers : ‘);
Readln(n1,n2,n3,n4,n5);
T1 := n1;
T1 := Max(t1,n2);
T1 := Max(t1,n3);
T1 := Max(t1,n4);
T1 := Max(t1,n5);
Writeln(‘Max number : ‘,t1);
End.
从上例看出,引入函数实际上是将一个复杂的问题划分成若干个易于处理的子问题,将编程化简的一种有效办法,而化简的方法是多种多样的,如前面已经做过求三个数中的最大数,所以可定义一个专门求三个数中最大数的函数(Max)。第一次用这个函数求出n1,n2,n3三个数中的最大数t1;第二次调用这个函数求出t1与n4,n5三个数中的最大数,也就是前三个数的最大数(已在t1中)和后面二个数再求一次,就得到五个数的最大数。因此,需要两次使用“求三个数中的最大数”,步骤如下:
①调用函数Max ( n1, n2, n3), 求出n1,n2,n3中的最大者 t1;
②调用函数Max ( t1, n4, n5 ),求出t1, n4, n5中的最大者t2;
③输出最大数 t2。
Program Exam41_b;
Var n1,n2,n3,n4,n5,t1: integer;
function Max(x1,x2,x3: integer): integer; {自定义函数Max}
Var XX: integer; {函数内部变量说明}
begin {函数体}
if X1>X2 then XX:=X1
else XX:=X2;
if X3>XX then XX:=X3;
Max:=XX
end;
Begin {主程序}
Write('Input 5 numb:');
Readln(n1,n2,n3,n4,n5); {输入五个数}
t1:=Max(n1,n2,n3); {用函数求n1, n2, n3的最大数}
t1:=Max(n4,n5,t1); {用函数求n4, n5, t1 的最大数}
Writeln('Max Number :', t1);
Readln
End.
主程序中两次调用自定义函数。自定义函数的一般格式为:
function 函数名(形式参数表): 类型; {函数首部}
局部变量说明部分;
begin
语句系列; {函数体 }
end;
函数中的形式参数接受调用函数时所传入的值,用来参与函数中的运算。
[例4.2]求任意输入的五个自然数的最大公约数。
解:⑴自定义一个专门求两自然数的最大公约数的函数GCD;
⑵调用自定义函数,第一次求前两个数的最大公约数;从第二次开始,用每次求得的最大公约数与下一个数再求两个数最大公约数,直到最后。本题共四次“求两个数的最大公约数”, 设输入的五个自然数分别是a1,a2,a3,a4,a5,采用如下步骤:
①求a1, a2两个数的最大公约数 → 存入a1;
②求a1, a3两个数的最大公约数 → 存入a1;
③求a1, a4两个数的最大公约数 → 存入a1;
④求a1, a5两个数的最大公约数 → 存入a1;
⑤ 输出 a1,此时的a1已是五个数的最大公约数。
Pascal程序:
Program Exam42;
Var a1,a2,a3,a4,a5: integder;
function GCD(x,y: integer): integer; {自定义函数 }
Var n:integer;
begin
While x mod y <>0 do
begin
n:=x; x:=y; y:=n mod y
end;
GCD:=y
end;
Begin {主程序 }
Write('input 5 Numper:');
readln(a1,a2,a3,a4,a5); {输入五个数}
Write('(',a1,',',a2,',',a3,',',a4,',',a5,')=');
a1:=GCD(a1,a2); {调用函数GCD }
a1:=GCD(a1,a3);
a1:=GCD(a1,a4);
a1:=GCD(a1,a5);
Writeln(a1);
readln
End.
函数的结果是一个具体的值, 在函数体中必须将所得到的运算结果赋给函数名;主程序通过调用函数得到函数的运算结果。调用函数的一般格式为:
函数名 (实在参数表)
调用函数时, 函数名后面圆括号内的参数必须有确定的值, 称为实在参数。调用时即把这些实际值传送给函数形参表中的相应形参变量。函数不是单独的语句, 只能作为运算赋值或出现在表达式中。
习题4.1
1. 数学上把从 1 开始的连续自然数相乘叫做阶乘。例如 把1*2*3*4*5 称作5的阶乘, 记为5!。 编写一个求n!的函数, 调用此函数求: D=
2.求从键盘输入的五个自然数的最小公倍数。
3.哥德巴赫猜想的命题之一是:大于6 的偶数等于两个素数之和。编程将6~100所有偶数表示成两个素数之和。
4.如果一个自然数是素数,且它的数字位置经过对换后仍为素数,则称为绝对素数,例如13。试求出所有二位绝对素数。
第二节 自定义过程
自定义函数通常被设计成求一个函数值,一个函数只能得到一个运算结果。若要设计成能得到若干个运算结果,或完成一系列处理,就需要自定义“过程”来实现。
[例4.3] 把前面[例2.2 ](输入三个不同的整数,按由小到大排序)改为下面用自定义过程编写的Pascal程序:
Program exam43;
Var a,b,c: integer;
Procedure Swap (var x,y: integer); {自定义交换两个变量值的过程 }
Var t : integer;
Begin {过程体}
t:=x; x:=y; y:=t {交换两个变量的值
end;
Begin {主程序}
Write('input a,b,c=');
Readln(a,b,c);
if a>b then swap (a,b); {调用自定义过程}
if a>c then swap (a,c);
if b>c fhen swap (b,c);
Writeln (a:6, b:6, c:6);
Readln
End.
程序中Procedure Swap是定义过程名,从作用来看,过程与函数是相似的,都能将复杂的问题划分成一些目标明确的小问题来求解,只不过函数有值返回而过程则没有。自定义过程的一般格式如下:
Procedure 过程名 (形式参数表); {过程首部}
局部变量说明部分;
begin
语句部分; {过程体部分}
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+1, A+2, A+3 …, A+10。
Pascal程序:
Program exam44;
var a,b,s,n: integer;
yes: boolean;
procedure sub(x: integer;var yy: boolean); {过程:求x是否为素数 }
var k,m: integer; { 用yy逻辑值转出 }
begin
k:=trunc(sqrt(x));
for m:=3 to k do
if odd(m) then
if x mod m=0 then yy:=false;
end;
begin {主程序 }
b:=3;
repeat
a:=b; {a 为第一个素数 }
repeat
yes:=true;
inc(b,2); {b是a后面待求的素数}
sub(b,yes); {调用SUB过程来确认b是否为素数 }
if yes then s:=b-a; {如果b是素数,则求出跨度s }
until yes;
until s > = 10;
for n:=a+1 to a+10 do
write(n:6);
writeln;
readln
end.
程序中的过程SUB,用来确定b是否为素数。过程名后面圆括号内的变量是形式参数,简称为形参。过程SUB(x: integer; Var yy: boolean) 中的x是值形参,而前面冠有Var的yy是变量形参。值形参只能从外界向过程传入信息,但不能传出信息;变量形参既能传入又能传出信息。本程序过程SUB中的x是由调用过程的实在参数b传入值,进行处理后,不需传出;而yy是把过程处理结果用逻辑值传出,供调用程序使用。
试把[例4.3]程序中的过程 SWAP(Val x,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间循环做以下步骤;
②用t1,t2分别累计合数n及n的质因数的各位数字之和,初值均为0;
③调用过程SUB3进行非素数判定,以布尔变量yes的真假值判定是否,yes的初值为true,如果为 (not true)非素数,就做步骤④,⑤,⑥;否则取新的n值,重复步骤③;
④调用SUB1,求n的各数字之和,传送给t1;
⑤调用SUB2,求n的各质因数,对于每个质因素都通过SUB1求它各位数字之和,将所有各质因数字传送给t2。
⑥如果t1=t2(各位数字之和等于它所有质因数的各数字之和),则输出此n。
PASCAL程序:
program exam45;
var n,t1,t2,tatol: integer;
yes: boolean;
procedure sub1(x:integer; var t:integer); {过程:分离x的各位数字 }
begin {并求各位数字之和 }
repeat
t:=t+x mod 10;
x:=x div 10;
until x=0
end;
procedure sub2(x: integer; var t: integer); {过程:分解质因数 }
var xx,tt:integer;
begin
xx:=2;
while x>1 do
if x mod xx=0 then
begin
tt:=0;
sub1(xx,tt);
t:=t+tt;
x:=x div xx
end
else inc(xx)
end;
procedure sub3(x: integer;var yy: boolean); {过程:判断x是否为素数 }
var k,m: integer;
begin
k:=trunc(sqrt(x));
for m:=2 to k do
if x mod m=0 then yy:=false;
end;
begin {主程序}
for n:=1 to 500 do
begin
t1:=0;t2:=0;
yes:=true;
sub3(n,yes); {调用过程求素数 }
if not yes then {如果非素数就… }
begin
sub1(n,t1); {调用过程求n的各位数字之和 }
sub2(n,t2); {调用过程求n的各质因数的数字之和 }
if t1=t2 then write(n:6); {打印合格的合数 }
end
end;
readln
end.
程序定义了三个过程SUB1,SUB2,SUB3,其中SUB2过程中又调用了SUB1。在过程中定义的变量或参数,只在本过程内部使用有效。这些变量称为局部变量。如SUB2中的xx只在SUB2中使用,属于局部变量。
习题:4.2
1.输入自然数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 < N < 2000) ,输出其不超过四个平方数之和的表示式。
第五章 Pascal的自定义数据类型
Pascal系统允许用户自定义的数据类型有:数组类型、子界类型、枚举类型、集合类型、记录类型、文件类型、指针类型。
第一节 数组与子界类型
[例5.1]总务室在商店购买了八种文具用品,其数量及单价如下表:
序号 1 2 3 4 5 6 7 8
品名 圆珠笔 铅笔 笔记本 订书机 计算器 三角板 圆规 文件夹
件数 24 110 60 16 26 32 32 42
单价 1.18 0.45 1.8 8.8 78.50 3.28 4.20 2.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程序:
Program Exam51;
Var a: array[1..8] of integer; {a数组为整数型}
s,b: array[1..8] of real; {s和b数组为实数型}
t: real;
i: integer;
Begin
t:=0;
for i:=1 to 8 do {输入并计算八种物品 }
begin
write('a[', i, ']=') ;
Readln(a[ i ]) ; {输入单价}
write('b[', i, ']=') ;
readln(b[ i ]); {输入件数}
s[ i ]:=a[ i ]* b[ i ]; t:=t+s[ i ]
end;
write('i':2, ' ':2);
for i:=1 to 8 do {打印物品序号}
write(i:8); {输出项宽度为8}
writeln;
write('a':2, ' ':2); {输出项宽度为2}
for i:=1 to 8 do {打印物品件数a数组}
write(a[ i ]:8); {输出项宽度为8}
writeln; {换行}
write('b':2, ' ':2);
for i:=1 to 8 do {打印物品件数b数组}
write(b[ i ]:8:2); {输出项宽度为8,小数2位}
writeln; {换行}
write('s':2, ' ':2);
for i:=1 to 8 do {打印物品计价s数组}
write(s[ i ]:8:2); {输出项宽度为8,小数2位}
writeln; {换行}
writeln('Totol=', t:8:2); {打印总价t}
Readln
end.
输出语句为 write(实数:n:m) 的形式时,则输出该实数的总宽度为n,其中小数m位,此时的实数不以科学计数形式显示。
程序中用来表示如物品件数和物品单价等属性相同的有序数据,Pascal语言把它归为数组。数组成员(分量)称为数组元素。数组必须在说明部分进行定义:确定数组名,数组分量(元素)的个数及类型。一般格式有:
Var 数组名:array[下标类型] of 数组元素类型 ;
本程序中a数组和b数组中8个元素的数据都是已知数据,可当作常量,用常量说明语句给数组元素赋初值,所以上面的程序Exam51可改为如下形式:
Program Exam51_1;
const a: array[1..8] of integer
=(24,110,60,16,26,32,32,42); {给a数组赋初值}
b:array[1..8] of real
=(1.18,0.45,1.80,8.8,78.50,3.28,4.20,2.16); {给b数组赋初值}
Var s: array[1..8] of real;
t: real;
i: integer;
Begin
t:=0;
for i:=1 to 8 do
begin
s[ i ]:=a[ i ]* b[ i ]; t:=t+s[ i ]
end;
write('i':2, ' ':2);
for i:=1 to 8 do write(i:8);
writeln;
write('a':2, ' ':2);
for i:=1 to 8 do write(a[ i ]:8:);
writeln;
write('b':2, ' ':2);
for i:=1 to 8 do write(b[ i ]:8:2);
writeln;
write('s':2, ' ':2);
for i:=1 to 8 do write(s[ i ]:8:2);
writeln;
writeln('Totol=', t:8:2);
Readln
end.
数组常量说明格式为:
Const 数组名:array[下标类型]of 数组元素类型=(常量表);
程序中对数组的输入、输出处理,常用循环语句控制下标,进行有序地直接操作每个数组元素。
[例5.2]编程输入十个正整数,然后自动按从大到小的顺序输出。
解:①用循环把十个数输入到A数组中;
②从A[1]到A[10],相邻的两个数两两相比较,即:
A[1]与A[2]比,A[2]与A[3]比,……A[9]与A[10]比。
只需知道两个数中的前面那元素的标号,就能进行与后一个序号元素(相邻数)比较,可写成通用形式A[ i ]与A[ i +1]比较,那么,比较的次数又可用1~( n - i )循环进行控制 (即循环次数与两两相比较时前面那个元素序号有关) ;
③在每次的比较中,若较大的数在后面,就把前后两个对换,把较大的数调到前面,否则不需调换位置。
下面例举5个数来说明两两相比较和交换位置的具体情形:
5 6 4 3 7 5和6比较,交换位置,排成下行的顺序;
6 5 4 3 7 5和4比较,不交换,维持同样的顺序;
6 5 4 3 7 4和3比较,不交换,顺序不变
6 5 4 3 7 3和7比较,交换位置,排成下行的顺序;
6 5 4 7 3 经过(1~(5-1))次比较后,将3调到了末尾。
经过第一轮的1~ (N-1)次比较,就能把十个数中的最小数调到最末尾位置,第二轮比较1~ (N-2)次进行同样处理,又把这一轮所比较的“最小数”调到所比较范围的“最末尾”位置;……;每进行一轮两两比较后,其下一轮的比较范围就减少一个。最后一轮仅有一次比较。在比较过程中,每次都有一个“最小数”往下“掉”,用这种方法排列顺序,常被称之为“冒泡法”排序。
Pascal程序:
Program Exam52;
const N=10;
Var a: array[1..N] of integer; {定义数组}
i,j: integer;
procedure Swap(Var x,y: integer); {交换两数位置的过程}
Var t:integer;
begin
t:=x; x:=y; y:=t
end;
Begin
for i:=1 to N do {输入十个数}
begin
write(i, ':');
Readln(a[ i ])
end;
for j:=1 to N-1 do {冒泡法排序}
for i:=1 to N-j do {两两相比较}
if a[ i ] < a[i+1] then swap(a[ i ], a[i+1]); {比较与交换}
for i:=1 to N do {输出排序后的十个数}
write(a[ i ]:6);
Readln
end.
程序中定义a数组的下标类型为 1.. N ,这种类型规定了值域的上界和下界,是从一个有序类型范围取出一个区段,所以称为子界类型,子界类型也是有序类型。
例[5.3] 用筛法求出100以内的全部素数,并按每行五个数显示。
解:⑴ 把2到100的自然数放入a[2]到a[100]中(所放入的数与下标号相同);
⑵ 在数组元素中,以下标为序,按顺序找到未曾找过的最小素数minp,和它的位置p(即下标号);
⑶ 从p+1开始,把凡是能被minp整除的各元素值从a数组中划去(筛掉),也就是给该元素值置 0;
⑷ 让p=p+1,重复执行第②、③步骤,直到minp>Trunc(sqrt(N)) 为止;
⑸ 打印输出a数组中留下来、未被筛掉的各元素值,并按每行五个数显示。
用筛法求素数的过程示意如下(图中用下划线作删去标志) :
① 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {置数}
② 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被2整除的数 }
③ 2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被3整除的数 }
……
2 3 4 5 6 7 8 9 10 11 12 13 14 15…98 99 100 {筛去被整除的数 }
Pascal程序:
Program Exam53;
const N=100;
type xx=1 .. N;      {自定义子界类型xx(类型名)}
Var a: array[xx] of boolean;
i,j: integer;
Begin
Fillchar(a,sizeof(a),true);
a[1] := False;
for i:=2 to Trunc(sqrt(N)) do
if a[I] then
for j := 2 to N div I do
a[I*j]:= False;
t:=0;
for i:=2 to N do
if a[i] then
Begin
write(a[ i ]:5); inc(t);
if t mod 5=0 then writeln
end;
readln
End.
程序中自定义的子界类型,在用法上与标准类型(如integer)相同,只是值域上界、下界在说明中作了规定,而标准类型的值域由系统内部规定,其上界、下界定义是隐含的,可直接使用。例如:
Type integer= -32768 ... 32768; Pascal系统已作了标准类型处理,不必再作定义。
[例5.4]在一次宴会上,有来自八个不同国家的宾客被安排在同一张圆桌就坐。A是中国人,会讲英语;B是意大利人,他能讲西班牙语;C是英国人,会讲法语;D是日本人,能讲汉语;E是法国人,会讲德语;F是俄国人,懂意大利语;G是西班牙人,能讲日语;最后一个是德国人,懂俄语。编程序安排他们的座位,使他们在各自的座位上能方便地跟两旁的客人交谈。
解:①根据题目提供条件与数据,建立如下关系代码表:
国家名 中国 意大利 英国 日本 法国 俄国 西班牙 德国
宾客代码 A B C D E F G H
语言代号 1 2 3 4 5 6 7 8
懂外语代号 3 7 5 1 8 2 4 6
总代码 A13 B27 C35 D41 E58 F62 G74 H86
表中总代码实际上是前三项代码的归纳:第一个字母表示哪国人;第二个数字表示本国语代号;第三个数字表示懂哪国外语。如A13,A表示中国人,1表示汉语(本国语),3表示会说英语。所以每个宾客的情况均用总代码(三个数据组成的字符串)表示;
②定义由8个元素组成的数组(NAME),元素类型为字符串类型(String);
③元素的下标号影响各人座位关系,必须满足后一个元素的下标号应与前一个元素字符串中的第三个数据相同。例如:若第一个位置总代码为A13,则第二个位置应根据A13中最后的3,安排C35。即A与C可以交谈。以此类推。
用字符串处理函数COPY,截取字符串的第一个字母作为宾客代码打印,再取第三个字符,用VAL将其转换成数字,将这个数字作为下标号,把这个下标号的元素安排在旁边(相邻);
④重复步骤③的方法,安排其后的元素,直到八个数据全部处理完为止。
Pascal程序:
Program Exam54;
const name : array[1..8]of string {定义字串类型数组并赋常量}
=('A13','B27','C35','D41','E58','F62','G74','H86');
Var i, code: integer; {整数类型}
x: 1..8; {子界类型}
s : string; {字符串类型}
Begin 
s:=copy(name[1],1,1); {截取第一个元素字串的第一个字符}
write(s:4); {确定第一个位置}
s:=copy(name[1],3,1); {截取元素字串的第三个字符作为相邻}
Val(s,x,code); {将字串s的值转换成数字存入 x}
for i:=1 to 7 do {确定后面7个位置}
Begin
s:=copy(name[x],1,1); {找到相邻者的代码}
write(s:4); {打印相邻者代码}
s:=copy(name[x],3,1); {确定下一个相邻元素}
Val(s,x,code);
end;
readln
End.
Pascal常用的字符串处理标准函数有7个:
设变量s,str,str1,str2均为字符串类型(string){多个字符};ch为字符类型(char){单个字符};
(1)copy(str,n,m)从字符串str的左边第n个开始截取m个字符;
如:copy(' Pascal ' ,3,2)的结果为'sc ' ;
(2)concat(str1,str2)将两个字串连接成为一个新的字串;
如:s:=str1+str2;同等于两串字符相加
(3)Length(str)求字串str的长度(字符个数);
(4)chr(x) 求x(x为1…255整数)的ASII代码对应的字符;
如:chr(65)结果为 'A'。
(5)ord(ch)求字符ch对应的ASCII代码值;如 ord ( 'A' )结果为65;
(6)pos(str1,str2)求字串str1在字串中开始的位置;
如: pos('sca','pascal')结果为3;
(7)upcase(ch)将字符ch转为大写字母,如 upcase( 'a' )结果为'A' ;
Pascal常用的字符串处理标准过程有4个:
(1)Val(str,x,code)将数字型字串转为数字并存入变量x中;
如:Val(‘768’,x,code),x值为768,code为检测错误代码,若code=0表示没有错误;
(2)str(n,s)将数字n转化为字串存入s中,如str(768,s)s的结果为 ' 768' ;
(3)insert(str1,str2,n)把字串str1插入在字串str2的第n个字符之前,结果在str2中;{此过程中的str2为变量形参,具有传入传出的功能};
(4)delete(str,n,m)从字串str的第n个开始,删除m个字符,把剩余的字符存在str中,{此过程中的str为变量形参,具有传入传出的功能};
[例5.5]一个两位以上的自然数,如果左右数字对称,就称为回文数,编程找出所有不超过6位数字的回文数,同时又是完全平方数的数。
如121是回文数,又是11的平方,所以是完全平方数。
解:①不超过6位数的完全平方数用循环在10~999范围产生(for i:=10 to 999) ;
②将完全平方数 (i*i)转成字串类型存入s中;
③逐个取s的左右字符,检查是否相同(对称),检查对数不超过总长度的一半;
④如果是回文数,就调用打印过程(Print)。
Program Exam55;
Var n, k, j ,t : integer;
s : string; {字符串类型 }
i: longint; {长整数类型 }
Procedure Print; {打印过程(无形参)}
begin
write(s : 10); inc(t); {打印s, 用t 计数 }
if t mod 6=0 then writeln {打印6个换行 }
end;
Begin
t:=0;
for i:=10 to 999 do
begin
str(i*i,s); {将完全平方数转换成字串 }
k:=length(s); {计算字串长度 }
n:=k div 2; {计算字串长度的一半 }
j:=1;
while j < = n do {取左右字符检查是否对称 }
if copy(s,j,1) < > copy(s,k+1-j,1) then j:=1000
else inc( j ) ; {若不对称让j=1000,退出循环 }
if j <1000 then Print { j <1000即是回文数,调打印 }
end;
writeln; writeln('Total=':8, t); {打印总个数 }
readln
End.
习题5.1
1.裴波那契数列:数列1、1、2、3、5、8、13、21…称为裴波那契数列,它的特点是:数列的第一项是1,第二项也是1,从第三项起,每项等于前两项之和。编程输入一个正整数N,求出数列的第N项是多少?(N不超过30)。
2.下面的竖式是乘法运算,式中P表示为一位的素数,编程输出此乘法竖式的所有可能方案。
3.节目主持人准备从N名学生中挑选一名幸运观众,因为大家都想争当幸运观众,老师只好采取这样的办法:全体同学排成一列,由前面往后面依顺序报数1,2,1,2,…,报单数的同学退出队伍,余下的同学向前靠拢后再重新由前往后1,2,1,2,…报数,报单数者退出队伍,如此下去最后剩下一人为幸运观众。编程找出幸运观众在原队列中站在什么位置上?(N由键盘输入,N < 255)。
4. 1267*1267=1605289,表明等式右边是一个七位的完全平方数,而这七个数字互不相同。编程求出所有这样的七位数。
5. 校女子100米短跑决赛成绩如下表,请编程打印前八名运动员的名次、运动员号和成绩。(从第一名至第八名按名次排列)
运动员号 017 168 088 105 058 123 142 055 113 136 020 032 089 010
成绩(秒) 12.3 12.6 13.0 11.8 12.1 13.1 12.0 11.9 11.6 12.4 12.9 13.2 12.2 11.4
6. 求数字的乘积根。正整数的数字乘积这样规定:这个正整数中非零数字的乘积。例如整数999的数字乘积为9*9*9,得到729;729的数字乘积为7*2*9,得到126;126的数字乘积为1*2*6,得到12;12从数字乘积为1*2,得到2。如此反复取数字的乘积,直至得到一位数字为止。999的数字乘积根是2。编程输入一个长度不超过100位数字的正整数,打印出计算数字乘积根的每一步结果。输出格式如下:
(N=3486784401)
3486784401
516096
1620
12
2
7. 有一组13个齿轮互相啮合,各齿轮啮合的齿数依次分别为6,8,9,10,12,14,15,16,18, 20,21,22,24, 问在转动过程中同时啮合的各齿到下次再同时啮合时,各齿轮分别转过了多少圈
8. 集合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个元素。
9. 一个素数,去掉最高位,剩下的数仍是素数;再去掉剩下的数的最高位,余留下来的数还是素数,这样的素数叫纯粹素数。求所有三位数的纯粹素数。
10. 自然数4,9,16,25等叫做完全平方数,因为22 =4, 32 =9, 42 =16,52 =25, 当某一对自然数相加和相减, 有时可各得出一个完全平方数。
例如: 8与17这对自然数: 17+8=25 17—8= 9
试编程,找出所有小于100的自然数对,当加和减该数对时,可各得出一个完全平方数。
第二节 二维数组与枚举类型
[例5.6]假设四个商店一周内销售自行车的情况如下面表一所示,
自行车牌号 永久牌 飞达牌 五羊牌
第一商店 35 40 55
第二商店 20 50 64
第三商店 10 32 18
第四商店 38 36 28
表一
几种牌号自行车的单价如表二所示。求各店本周出售自行车的总营业额。
单价 元
永久牌 395
飞达牌 398
五羊牌 384
表二
解:①把表一看成是由行(每个店占一行)与列(每种牌号占一列)共同构成的数据组,按表格排列的位置顺序,用A数组表一各数据表示如下:
A[1,1]=35 A[1,2]=40 A[1,3]=55 {第一行共三个数据}
A[2,1]=20 A[2,2]=50 A[2,3]=64 {第二行共三个数据}
A[3,1]=10 A[3,2]=32 A[3,3]=18 {第三行共三个数据}
A[4,1]
同课章节目录