第五章、选择结构
本章讨论程序的分支结构,其主要知识是布尔运算(逻辑运算)。
第一节、布尔运算(逻辑运算)
要判断“A>B”是否成立,其结果不是一个具体的数值,而是“真”或“假”,即“是”或“否”的问题。这类问题在我们日常生活中是很多的,诸如这类判断的问题,其结果都是只有两个:真或假,这就是我们所说的布尔运算(逻辑运算)。
一、 布尔常量和布尔变量
布尔型的常量或变量的值只有两个:TRUE(真)和FALSE(假)。要把一个变量定义成布尔类型,用的数据类型是:BOOLEAN。例如程序:
var a,b:boolean;
begin
a:=true;
b:=false;
……
end.
二、
布尔表达式
布尔表达式有以下两种操作:
1、 关系运算符:=;<>; >; <; >=; <=,是用来进行关系操作(对比)运算的符号,其结果为BOOLEAN型。如:2=3,其结果为FALSE。*注意:这里的“=”与赋值符号“:=”是完全不同的,其作用和结果均不同。
2、 逻辑运算符:AND(逻辑和);OR(逻辑或);NOT(逻辑非)。是用来进行逻辑值的
逻辑运算的。如:(2=3)AND (4<>3),值为FALSE。
布尔表达式的运算顺序是:()à函数àNOTà*,/.DIV,MOD,AND,+,-,ORà>,<,>=,<=,<>,=。
布尔表达式中的逻辑运算如下表所示:a和b均为布尔型表达式或常/变量.
a |
b |
A and b |
A or b |
Not a |
Not b |
true |
false |
false |
true |
false |
True |
true |
true |
true |
true |
false |
False |
false |
true |
false |
true |
true |
False |
false |
false |
false |
false |
true |
True |
由上可以看出:
1、 用AND运算时,左右两个值同为TRUE时,运算结果才为TRUE,即两个条件同时满足,结果才为TRUE。这就是我们平常所说的“和”。
2、 用OR运算时,左右两个值只需有一个为TRUE,运算结果就为TRUE,即两个条件满足其中一个,结果就为TRUE。这就是我们平常所说的“或”。
3、 用NOT运算时,只是把其后的逻辑值取反,即“非”。
4、 例:[例4、1]
Program q41;Var a,b,c,d:integer;
P:boolean;
Begin
A:=1;
B:=2;
C:=3;
D:=4;
P:=(a=b);
Writeln(p);
P:=((a<b) and (c<d));
Writeln(p);
Writeln((a>d) or (c>b));
End. |
说明四个整数型变量
说明一个布尔型变量
程序开始
赋值
赋值
赋值
赋值
把(A=B)这个逻辑运算的结果赋给P,即P的值为FALSE
打印P
把((a<b) and (c<d))这个逻辑运算的结果赋给P
打印P
打印(a>d) or (c>b)这个逻辑运算的结果
程序结束 |
程序运行结果是:
false
true
true
由上可以看出:逻辑运算中的关系运算均用括号“()”括起来。关系运算/逻辑运算的结果也是一个值(BOOLEAN型),所有布尔运算也是表达式,可以赋给一个变量,也可以直接用输出语句输出。打印输出时,屏幕上就显示“false”或“true”。
第二节、条件语句
条件语句是用一个布尔表达式的值来决定程序的走向。即程序提供一个分支,由布尔表达式的值来决定程序究竞运行哪个分支。即程序已经不是顺序结构了,而是提供了一个分支结构。每次只可能运行其中的一个分支。如下图所示: ˇ
布尔表达式
ˇ
ˇ
ˇ
ˇ
条件语句有两种格式:
1、if <布尔表达式> then <语句>;
2、if <布尔表达式> then <语句1> else <语句2>;
格式1的作用是:如果布尔表达式值为TRUE(即该条件满足),则运行语句,否则不运行任何语句。
格式2的作用是:如果布尔表达式值为TRUE(即该条件满足),由运行语句1,否则(即布尔值为FALSE,亦即条件不满足)就运行语句2。注意:只有条件语句结束时才有分号。
注意:如果条件语句中的分支语句不止一句,可用“begin……end;”来框住,加以区别。如:以下两个程序都为从键盘输入1个整数,打印出它的算术平方根。[例4、2]:
Program q421;Var a:integer;
Begin
Readln(a);
If (a<0) then
Begin
Writeln(‘WRONG!’);
End else
Begin
Writeln(a);
Writeln(sqrt(a):8:2);
End;
End. |
Program q421;Var a:integer;
Begin
Readln(a);
If (a<0) then Writeln(‘WRONG!’) else Writeln(sqrt(a):8:2);
End. |
条件语句的嵌套:条件语句是可以嵌套的,例如:
if a>0 then if a>1 then …… else …… else ….;
上述语句看起来无法理解,但如果我们把它改写为以下形式时,就一目了然了:
if a>0 then begin
if a>1 then begin
……
end
else begin
……
end
else begin
……
end;
也就是说,第二个IF语句只是第一个IF语句中的一部分,即嵌入的一个IF语句。
例:输入一个年份,判断它是否闰年。我们知道,每四年中有一年是闰年,即有366天,而其余三年是平年,只有365天,而按照规定:1、如果哪一年的年份能被4整除,则该年一般为闰年;2、这样,每100年又会少一天,所以又规定如果该年能被4整除,又能被100整除,则认为该年不是闰年,而是平年;3、这样,每400年又会多出一天,所以又规定,如果哪一年能被400整除,则该年又是闰年。
由上可知:1980,1996,1984年均为闰年,1900年为平年,而2000年为闰年。
程序如下:[例4、3]
Program q43;Var y:integer;
Begin
Readln(y);
if (y mod 4=0) then begin
if (y mod 100=0) then begin
if (y mod 400=0) then begin
writeln('run');
end else begin
writeln('ping');
end;
end else begin
writeln('run');
end;
end else begin
writeln('ping');
end;
end. |
|
第三节、多分支语句
IF语句只能使程序有两个分支,当遇到需要有两个以上分支时,IF语句就很不适用了,这时我们可以用CASE语句,它能使程序有很多个分支。其效果如下图:
其格式为:
CASE 表达式 OF
常量1:语句序列1;
常量2:语句序列2;
……
常量N:语句序列N;
else 语句序列N+1;
END;
其中语句序列如果只有一句,可直接写在常量后的冒号后;如果语句序列有很多句,则应该用BEGIN……END加以框住。
CASE语句的作用是,根据表达式,表达式可以有多个值,分别对应于常量1、2等值时,就运行该常量后所对应的语句。
例:输入1到7之间的某个整数,打印出其对应的星期的英语名:[例4、4]:
program q44;
var n:integer;
begin
write(‘n=’);
readln(n);
case n of
1:writeln(‘Monday’);
2:writeln(‘Tuesday’);
3:writeln(‘Wednseday’);
4:writeln(‘Thursday’);
5:writeln(‘Friday’);
6:writeln(‘Saturday’);
7:writeln(‘Sunday’);
else writeln(‘WORNG!’);
end;
end.
例:输入一个学生的数值化成绩,把它转化为等级化成绩。即100-90是A,89-80是B,79-70是C,69-60是D,59-0是E。[例4、5];
Program q44;Var s:integer;
G:char;
Begin
Write(‘Input the score:’);
Readln(s);
Case s div 10 of
10,9:g:=’A’;
8:g:=’B’;
7:g:=’C’;
6:g:=’D’;
else g:=’E’;
end;
writeln(s,’ ‘,g);
end. |
用S DIV 10这个表达式作条件;
当 S DIV 10等于10或9时,表示S是90至于100之间的值 |
第四节、标号说明及转移语句
此节不用掌握
在几乎所有语言中,都有GOTO(转移)语句,其作用是当程序运行到该句时,自动转移到其指定的标号(行号)语句去执行。
说明语法:LABEL 标号; 如:LABEL 10,20;
转移语句用法:GOTO 标号;
例:[例4、5]:
program q45;
label 10;
begin
10:
write(‘*’);
goto 10;
end.
运行上述程序时,程序将在屏幕不停地打印出“*”,而不会停止,必须由用户按下CTRL+BREAK才能中断。
练习
1、 设X,Y,Z的值分别是FALSE,TRUE,FLASE。写出下列逻辑表达式的值:
not x and not y;
true and x or y;
(x and z) or (z and y);
x or z and y;
2、 编写一个程序,功能是从键盘输入一个整数,判断它是否二位数,如果是,就打印它,然后结束程序,否则继续要求输入数。
3、 编写一个程序,功能是从键盘输入三个整数,打印出其中最大的一个值。
4、 编写一个程序,功能是从键盘输入1—12中的某一个数字,由电脑打印出其对应的月份的英语名称。
5、 以下程序的功能是从键盘输入一个式子,它只有三个字符,第一个及第三个都是数字,中间那个是运算符,程序能把它的结果打印出来。试在程序空中填上相应的语句。
注意:计算机是不懂得把输入的字符串进行计算的,我们必须自己动手把其中的数字转化成数值型的数据,这其中我们使用了VAL函数,如程序中的:Val(s[1],a,c),是把S字符串中的第一个字符转换为数值A,同时输出了一个错误代码C(其实对我们是没有用的)。
Var a,b,d:real; C:word;
S:string[3];
Begin
Readln(s);
Val(s[1],a,c);
;
Case s[2] of
‘+’:d:=a+b;
‘-’:d:=a-b;
‘*’: ;
‘/’:d:=a/b;
end;
writeln(s,’=’, );
end. |
把S定义成三个字符的字符串;
把S串中的第一个字符转换为数值;
把S串中的第三个字符转换为数值;
用S串中的第二个字符作为条件表达式; |
第六章、重复结构
重复结构就是循环结构,是指某些语句需要重复执行而设定的程序结构。在PASCAL语言中,共有三种重复结构语句,功能各有不同。
第一节、直到语句
直到循环语句的语法格式是:
repeat
语句序列;(循环体)
until 布尔表达式;
其作用是:重复执行语句序列(循环体),直到布尔表达式的值为TRUE为止。即,当执行完一次语句序列后,布尔表达式的值已经为TRUE了,这时循环将不会再被执行,而转向执行UNTIL语句以下的语句。
例:计算M=1+2+3+4+……,直到M的值大于5050为止。[例:5、1]
var m,I:integer;
begin
m:=0;
I:=0;
Repeat
I:=I+1;
M:=m+I;
Until m>5050;
Writeln(I,’ ’,m);
End.
在上述程序中,我们使用了PASCAL中的两个作用强大的概念:累加和循环。
累加:我们在上述程序中没定了两个累加器:I,M。累加器初值我们在第一句中设定了为0,之后每次运行一次I:=I+1后,I的值就比原来大1。每运行一次M:=M+I后,M的值就被M+I所替代。
循环:这里我们使用的是直到循环,即重复执行循环体中的两个语句,直到M>5050这个条件满足为止(即这个布尔表达式的值为TRUE为止)。
上述程序运行后,会在输出屏幕上显示两个值:101 5151。即当I的值为101时,这时所算得的M的值为5151。亦即,1+2+3+……101=5151。
象上述这种X=1+2+3+……这种加法,我们就把它叫累加,这里的X就是累加器,一般初值为0。
而N=1*2*3*4*5*6*……这种乘法我们把它叫累乘,这里N就是累乘器,一般初值为1(为什么?)。
一般的:1*2*3*……N,我们把这个式子的结果叫做N的阶乘(N!)。如:4!=1*2*3*4。
例:计算19![例5、2]
var I:integer;
x:longint;
begin
I:=0;
X:=1;
Repeat
I:=I+1;
X:=x*I;
Until I=19;
Writeln(x);
End.
当程序开始时,I的初值被定为0,X的初值被定为1(累乘器)。然而开始进入循环,每次I的值比原来增加1,然后再乘进X中去,直到I等于20时,最后一次把I乘进X后,这时I=20这个条件已经满足(I=20的值已经为TRUE),所以循环就被退出,而程序转向执行UNTIL以后的语句:WRITELN(X);。
请大家想一想,为什么X要定义为LONGINT型。
第二节、当语句
当语句的语法格式是:
while 布尔表达式 do begin
语句序列;(循环体)
end;
其作用是,当布尔表达式的值为TRUE时,才会运行语句序列(循环体),否则循环将不会被执行,即从循环头部就退出,而转向执行END后的语句。
例:计算19![例5、3]
var I:integer;
x:longint;
begin
I:=0;
X:=1;
While I<19 do begin
I:=I+1;
X:=x*I;
End;
Writeln(x);
End.
请大家把此程序与上一节的[例5、2]进行比较,看两种循环在运用时有何不同。
WHILE语句是在循环开始时就判断布尔表达式的值时否为TRUE,如果为TRUE,就进入循环,运行循环体,如果为FALSE,就不运行循环体,而直接转向执行END后的语句WRITELN(X);。
REPEAT与WHILE循环的示意框图如下所示:
REPEAT WHILE
从上述框图中可以看出,要使用循环语句时,必须要确定循环体及条件(布尔表达式)两个重要因素,亦即首要考虑的是:我要重复执行哪些语句,我要重复到什么时候为止!
[例5、4],从键盘上输入两个整数M,N,求它们的最大公约数。
分析:我们只需从M,N中更小的一个数开始,每次让其减1,直到这个数能同时被M和N数整除为止。在下述程序中,我们在程序头部调用了CRT单元,是为了使用CLRSCR语句来清屏,即把输出屏幕上的字符清除干净。
Uses crt; {调用CRT单元}
Var m,n,x:integer;
Begin
Clrscr; {清屏}
Write(‘Please input 2 numbers:’)
Readln(m,n);
If m>n then x:=n else x:=m;
While (n mod x<>0) or (m mod x<>0) do begin
x:=x-1;
End;
Writeln(x);
End.
上述程序如果改用REPEAT语句来做的话,程序为:
uses crt;
var m,n,x:integer;
begin
write(‘Please input 2 numbers:’)
Readln(m,n);
If m>n then x:=n+1 else x:=m+1;
Repeat
X:=x-1;
Until (m mod x=0) and (n mod x=0);
Writeln(x);
End.
请大家考虑上述两个程序为何会有这样有不同之处。
第三节、FOR循环语句
前面所计的两个语句都是在未知循环次数的情况下而用的循环语句,但在程序中,如果我们已经知道循环的次数而来编程序的话,就可以使用FOR循环语句,这也是PASCAL及其它高级语言中用得最多的语句。其语法格式有两种,如下:
(1) 增量为1:
for 变量名:=初值 to 终值 do begin
语句序列(循环体);
end;
(2) 增量为-1:
for 变量名:=初值 downto 终值 do begin
语句序列(循环体);
end;
变量名的类型由程序头部中定义,而其初值、终值必须和它是同一类型。该变量的类型是能是有序数据类型。
上述两种格式都是用变量的初值与终值来规定循环的次数。如以下两个小程序:
Var I:integer;Begin
For I:=1 to 5 do begin
Write(I);
End;
End.
运行结果:
12345 |
Var I:integer;Begin
For I:=5 downto 1 do begin
Write(I);
End;
End.
运行结果:
54321 |
由上可以看出FOR循环的作用。
[例5、5]:从键盘输入一个字符串,把它按正序及逆序分别输出:
uses crt;
var s:string;
l,I:integer;
begin
clrscr;
write(‘Please input the string:’);
readln(s);
l:=length(s);
for I:=1 to l do begin
write(s[I]);
end;
writeln;
for I:=l downto 1 do begin
write(s[I]);
end;
end.
[例5、6]计算
uses crt;
var s,a:integer;
begin
clrscr;
s:=0;
for a:=1 to 10 do begin
s:=s+a*a;
end;
writeln(s);
end.
[例5、7]:计算:1+3+5+7+……101的值:
uses crt;
var m,n:integer;
begin
clrscr;
m:=0;
for n:=0 to 50 do begin
m:=m+(2*n+1);
end;
writeln(m);
end.
请大家注意上述程序中的几个小技巧,一个是FOR N:=0 TO 50,共循环51次;一个是M:=M+(2*N+1),其是的2*N+1得到的是一序列的奇数。
第四节、多重循环语句
多重循环语句即循环嵌套,也就是一个循环语句的循环体中还有循环语句。
[例5、8]编程序打印九九乘法表:
uses crt;
var I,j:integer;
begin
clrscr;
for I:=1 to 9 do begin
for j:=1 to 9 do begin
write(j:1,’*’,i:1,’=’,I*j:2);
end;
writeln;
end;
end.
运行结果:
1*1= 1 |
2*1= 2 |
3*1= 3 |
4*1= 4 |
5*1= 5 |
6*1=6 |
7*1= 7 |
8*1= 8 |
9*1= 9 |
1*2=2 |
2*2= 4 |
3*2= 6 |
4*2= 8 |
5*2=10 |
6*2=12 |
7*2=14 |
8*2=16 |
9*2=18 |
1*3=3 |
2*3= 6 |
3*3= 9 |
4*3=12 |
5*3=15 |
6*3=18 |
7*3=21 |
8*3=24 |
9*3=27 |
1*4=4 |
2*4= 8 |
3*4=12 |
4*4=16 |
5*4=20 |
6*4=24 |
7*4=28 |
8*4=32 |
9*4=36 |
1*5=5 |
2*5=10 |
3*5=15 |
4*5=20 |
5*5=25 |
6*5=30 |
7*5=35 |
8*5=40 |
9*5=45 |
1*6=6 |
2*6=12 |
3*6=18 |
4*6=24 |
5*6=30 |
6*6=36 |
7*6=42 |
8*6=48 |
9*6=54 |
1*7=7 |
2*7=14 |
3*7=21 |
4*7=28 |
5*7=35 |
6*7=42 |
7*7=49 |
8*7=56 |
9*7=63 |
1*8=8 |
2*8=16 |
3*8=24 |
4*8=32 |
5*8=40 |
6*8=48 |
7*8=56 |
8*8=64 |
9*8=72 |
1*9=9 |
2*9=18 |
3*9=27 |
4*9=36 |
5*9=45 |
6*9=54 |
7*9=63 |
8*9=72 |
9*9=81 |
注意:循环有嵌套时,必须分清层次,切不可把循环进行交叉。
[例5、9]编程序分别打印以下三图:
(1) (2) (3)
***** ***** *****
***** ***** *****
***** ***** *****
***** ***** *****
***** ***** *****
(1)Uses crt;
Var I,j:integer;
Begin
Clrscr;
For I:=1 to 5 do begin
For j:=1 to 5 do begin
Write(‘*’);
End;
Writeln;
End;
End. |
(2)Uses crt;
Var I,j:integer;
Begin
Clrscr;
For I:=1 to 5 do begin
Write(‘ ’:20+i);
For j:=1 to 5 do begin
Write(‘*’);
End;
Writeln;
End;
End. |
(3)Uses crt;
Var I,j:integer;
Begin
Clrscr;
For I:=1 to 5 do begin
Write(‘ ’:20-I);
For j:=1 to 5 do begin
Write(‘*’);
End;
Writeln;
End;
End. |
请大家注意看清上述三个小程序,其功能是分别打印出上述三个由“*”组成的小图形。三个图形的不同之处是:第一个直上直下,是个矩形;第二个是左斜的平行四边形;第三个是右斜的平行四边形。所以三个对应的程序也就有所不同,第(2)、(3)个程序比第(1)个多了一句,即加粗加线的那一句。这两句的作用是使每一行开头打印几个空格,即让图形左或右斜。WRITELN的作用是打印完一行后换行。
[例5、10]编程打印下列图形:
1
222
33333
4444444
555555555
Uses crt;Var I,j:integer;
Begin
Clrscr;
For I:=1 to 5 do begin
Write(‘ ’:20-I);
For j:=1 to 2*I-1 do begin
Write(I:1);
End;
Writeln;
End;
End. |
清屏
打印每一行前的20-I个空格,这样每行都比上一行左移
每一行打印2*I-1列
打印该行行数 |
[例5、11]打印1—100间的所有素数:
素数,即为除了1和它本身外没有另外的因数的整数。所以我们判断一个数N是否素数,可以用2至N-1所有数去除N,如果没有一个数能被N整除,则N为素数。
当然,其实我们可以不用用2至N-1这第多的数去除,而只需用2至不大于N的平方根的整数去除N即可(为什么)?
这里我们的程序就用2至TRUNC(SQRT(N))来判断,到后面我们还会谈到:如果要判断一个数是否素数,可只用小于TRUNC(SQRT(N))的所有素数去除即可。
Var I,j:integer; P:boolean;
Begin
For I:=2 to 100 do begin
P:=true;
For j:=2 to trunc(SQRT(I)) do begin
If I mod j=0 then p:=false;
End;
If p then write(I:5);
End;
End. |
循环从2至100
再判断I是否素数前,先把判断器P的值设为TRUE
用2至trunc(SQRT(I))的数来除I
如果I能整除J,则P的值改为FALSE
如果P的值仍为TRUE,则I就是素数,打印出来 |
[例5、12]以下是A,B,C三人说的话:
A:“B在说谎”;B:“C在说谎”;C:“A、B都在说谎”。现在问,到底谁说真话,谁说谎?
分析:A、B、C三人,要么说谎,要么说真话,即三个的状态要么为FALSE,要么为TRUE,所以,可让A、B、C三个变量进行循环,循环初值为TRUE,终值为FALSE。而三个人所说的话即为三个逻辑表达式,其值也为TRUE或FALSE,并且与A、B、C的值是有关系的。A、B、C三个所说的话转化为逻辑表达式即为:
A:B=FLASE;
B:C=FALSE;
C:(A=FALSE) AND (B=FALSE)
以上三个逻辑表达式的值中,TRUE的个数应该与A、B、C三个变量中TRUE的个数相同。并且,每一个变量的值应该与其对应的话的逻辑表达式的值相等。如:A应该等于(B=FALSE)这个逻辑表达式。程序如下:
Var a,b,c:boolean;Begin
For a:=false to true do begin
For b:=false to true do begin
For c:=false to true do begin
If (a=(b=false)) and (b=(c=false)) and (c=((a=false) and (b=false)))
then Begin
Writeln(a:10,b:10,c:10);
End;
End;
End;
End;
End. |
第五节、练习
1、 随机产生一些1—100之间的整数,直到产生的数为50为止。
2、 计算1—1000之间能同时被3和5整除的整数的和。
3、 打印下列图形:
1
121
12321
1234321
12321
121
1
4、 一百匹马驮一百块瓦,一匹大马可以驮3块,一匹母马可驮2块,小马2匹可驮1块。试编程求需要各种马多少匹?
5、 有三种纪念邮票,第一种每套一张售价2元,第二种每套一张售价4元,第三种每套9张售价2元。现用100元买了100张邮票,问这三种邮票各买几张?
6、 赵、钱、孙、李、周五人围着一张圆桌吃饭。饭后,周回忆说:“吃饭时,赵坐在钱旁边,钱的左边是孙或李”;李回忆说:“钱坐在孙左边,我挨着孙坐”。结果他们一句也没有说对。请问,他们在怎样坐的?
7、找数。一个三位数,各位数字互不相同,十位数字比个位、百位数字之和还要大,且十位、百位数字之和不是质数。编程找出所有符合条件的三位数。
注:1. 不能手算后直接打印结果。
2. “质数”即“素数”,是指除1和自身外,再没有其它因数的大于1的自然数。
8、选人。一个小组共五人,分别为A、B、C、D、E。现有一项任务,要他们中的3个人去完成。已知:(1)A、C不能都去;(2)B、C不能都不去;(3)如果C去了,D、E就只能去一个,且必须去一个;(4)B、C、D不能都去;(5)如果B去了,D、E就不能都去。编程找出此项任务该由哪三人去完成的所有组合。
9、输入一个字符串,内有数字和非数字字符。如A123X456Y7A,302ATB567BC,打印字符串中所有连续(指不含非数字字符)的数字所组成的整数,并统计共有多少个整数。
10、A、B、C三人进入决赛,赛前A说:“B和C得第二,我得第一”;B说:“我进入前两名,丙得第三名”;C说:“A不是第二,B不是第一”。比赛产生了一、二、三名,比赛结果显示:获得第一的选手全说对了,获得第二的选手说对了一句,获得第三的选手全说错了。编程求出A、B、C三名选手的名次。
11、甲、乙、丙、丁四人共有糖若干块,甲先拿出一些糖分给另外三人,使他们三人的糖数加倍;乙拿出一些糖分给另外三人,也使他们三人的糖数加倍;丙、丁也照此办理,此时甲、乙、丙、丁四人各有16块,编程求出四个人开始各有糖多少块。
12、截数问题: 任意一个自然数,我们可以将其平均截取成三个自然数。例如自然数135768,可以截取成13,57,68三个自然数。如果某自然数不能平均截取(位数不能被3整除),可将该自然数高位补零后截取。现编程从键盘上输入一个自然数N(N的位数<12),计算截取后第一个数加第三个数减第二个数的结果。
13、从键盘输入一段英文,将其中的英文单词分离出来:已知单词之间的分隔符包括空格、问号、句号(小数点)和分号。
例如:输入:There are apples; oranges and peaches on the table.
输出:there
are
apples
oranges
and
peaches
on
the
table
14、山乡希望小学收到一箱捐赠图书,邮件上署名是“兴华中学高二班”,山乡希望小学校长送来了感谢信,可是兴华中学高二年级有四个班,校长找来了四个班的班长,问他们是哪 个班做的这件好事。一班的班长说:“是四班做的。”二班的班长说:“是三班做的好事。”三班的班长说:“不是我们班。” 四班的班长说:“三班的班长说的不对。”
四个班的班长都说不是自己班做的,这就难坏了校长,后来得知四个班的班长中有两个 说得是真话,有两个没有说真话,请你利用计算机的逻辑判断编一个程序,找出究竟是哪个班做了这件好事。不能手算后直接打印结果。
15、A,B,C,D,E五个人合伙夜间捕鱼,凌晨时都疲惫不堪,各自在河边的树丛中找地 方睡着了,日上三竿,E第一个醒来,他将鱼数了数,平分成五分,把多余的一条扔进河中,拿走一份回家去了,D第二个醒来,他并不知道有人已经走了,照样将鱼平分成五分,又扔掉多余的一条,拿走自己的一份,接着C,B,A依次醒来,也都按同样的办法分鱼(平分成 五份,扔掉多余的一条,拿走自己的一份),问五人至少合伙捕到多少条鱼。
也许你能用数学办法推出鱼的条数,但我们的要求你编出一个程序,让计算机帮你算出鱼的总数。
16、试编程找出能被各位数字之和整除的一切两位数。
17、一个正整数的个位数字是6,如果把个位数字移到首位,所得到的数是原数的4倍,试编程找出满足条件的最小正整数。
18、某本书的页码从1开始,小明算了算,总共出现了202个数1,试编程求这本书一共有多少页?
19、从键盘上输入两个不超过32767的整数,试编程序用竖式加法形式显示计算结果。
例如: 输入 123, 85
显示: 123
+ 85
---------
208
20、有30个男人女人和小孩同在一家饭馆进餐,共花了五十先令,其中男宾3先令,女宾2先令,小孩1先令。试编程求出男人女人小孩各多少人?
第七章、数组、集合与自定义数据类型
第一节、数组
在一个程序中,如果所要用到的常量、变量不多,并且彼此之间无序列化的联系,我们一般定义成不同的常/变量名即可。但如果要用到的常/变量个数很多,彼此之间有着序列化的联系时,我们就会把它们定义成一个数组。数组—即一序列的数(各种类型的数据)组成的一个数据的序列。这些数据共用一个名称,只不过下标不同。
例如:在我们的数学学习中,在解一元二次方程时,方程有两个解,我们会分别用X1、X2来表示。而在PASCAL语言中,我们用X[1]、X[2]来表示,即下标是放在中括号中的。
一、一维数组
数组如果要使用的话,就必须先在程序头部的常量/变量说明中先说明,说明语法是:
变量名:ARRAY[下标初值..下标终值] OF 数据类型;
如:VAR N:ARRAY[1..10] OF INTEGER;
作用是说明一个名为N的整数型数组,可用的下标为1至10,即可用10个变量。
再如:CONST M:ARRAY[1..5] OF CHAR=(‘A’,‘B’,‘C’,‘D’,‘E’);
作用是说明了一个名为M的字符型数组常量,下标范围为1至5,因为是常量,所以在后面指明了这五个常量的值分别为:‘A’,‘B’,‘C’,‘D’,‘E’。
在程序头部说明了数组后,在程序中就可以使用了,使用方法为:常/变量名[下标号]。如,M[1]即调用M[1]这个常量,其值为‘A’。
[例6、1]从键盘输入10个整数,然后把它们排序,从大到小打印出来。
分析:排序是各种语言中的一个必需掌握的要点。排序有很多种方法,但不论是哪种方法,都是把这些据存放在一个数组中,然后再对其进行排序操作。排序一般有以下几种方法:
1、 双数组法:再定义另一个与存放数据数组同类型的数组,然后把数据数组中最大的一个数找出来,存放为另一数组中的第一个;再找第二、第三个等等。其中的细节问题就是:在数据数组中找到最大的一个后,就把它的值赋成一个非常小的值,然后再找最大的一个,这样就能顺序把数据从大到小存放到另一个数组中,也即排好了序。
2、 冒泡法:这是最常用的一种排序方法,其实质是:先把数据存放在数组中,然后从第一个开始,分别与其后所有数据进行比较,如果第一个比其后某个数据小,则交换它们的值,一直到第一个与其后所有数据比较完,这时第一个数据就是最大的一个;然后再把第二个数据再与其后数据进行比较,比较完后,第二个数据则为第二大的,这样直到倒数第二个数据比较完后,整个数组就已经按从大到小的顺序排列了。其作用示意如下:
假设我们已经把6个数据分别存放在N[1]至N[6]中,其值分别为:3,1,5,9,2,6。
交换前的值为: |
3,1,5,9,2,6 |
第一步,把第一个值与其后第一个进行比较,这时3>1,所以值不变: |
3,1,5,9,2,6 |
第二步:把第一个值与其后第二个进行比较,这时3<5,所以值交换: |
5,1,3,9,2,6 |
第三步:把第一个值与其后第三个进行比较,这时5<9,所以值交换: |
9,1,3,5,2,6 |
…… |
…… |
当第一个值与其后所有值比较完后,第一个值已经是最大的,数组值为: |
9,1,3,5,2,6 |
这时,重复上述第一步的操作,只是把第一个值换成第二个值,第一个值即第二个值与其后第一个值进行比较,这时1<3,所以交换其值: |
9,3,1,5,2,6 |
第二个值与其后所有值比较完后,数组值为: |
9,6,1,3,2,5 |
再重复进行第三个值与其后值的比较,直到第五个值与第六个值比较完后,这时数组的值已经变为: |
9,6,5,3,2,1 |
至此,数组已经按从大到小的顺序排好了。 |
|
程序如下 :[例6、1]
Var n:array[1..10] of integer;I,j,t:integer;
Begin
For I:=1 to 10 do Readln(n[I]);
For I:=1 to 9 do begin
For j:=I+1 to 10 do begin
If n[I]<n[j] then begin
T:=n[I];
N[I]:=n[j];
N[j]:=t;
End;
End;
End;
For I:=1 to 10 do begin
Write(n[I]:5);
End;
End. |
说明一个数组型变量从键盘读入10个数据存放在数组N中
参加比较的第一个数据为第1至第9个。
第二个数据为第一个数据之后所有的数据
如果n[I]<n[j]则用以下三句来交换其位置
打印排序后的结果 |
二、二维数组
1、 矩阵:我们在PASCAL语言中接触到的一般是数字矩阵,如:
1 2 3 4 5 6
3 4 5 6 7 9
1 5 8 9 4 2
7 5 3 2 1 7
如果要存放这样的矩阵数据,我们可以定义几个数组来存放,每个数组存放一行或一列,但最好的办法是定义一个二维数组来存放。二维数组有两个下标,可以分别对应矩阵中的行号、列号,从而能更加方便的存取数据。定义的语法是:
变量名:ARRAY[下标初值1..下标终值1,下标初值2..下标终值2] OF 数据类型;
例如:VAR A;ARRAY[1..4,1..6] OF INTEGER;
数组A就可存放上述矩阵的所有数值。或者定义一个常量:
CONST B:ARRAY[1..4,1..6] OF INTEGER=((1,2,3,4,5,6),
(3,4,5,6,7,9),
(1,5,8,9,4,2),
(7,5,3,2,1,7));
这样我们就能在程序直接使用,如:B[1,5]是指第一行的第五个数据,即5;B[3,2]指第三行第二个数据,即5,等等。
第二节、集合
集合是一序列有共同性质或联系的数据组成的一个集体。如日常生活中所说的:一个班的全体同学;一个书架上所有的书等。而在PASCAL语言中,集合一般都是指一系列的数值或字符等数据,如:小于10的正整数;26个英语字母等。集合也象常/变量一样有自己的名字,即集合名,它是在程序头部象定义变量一样来定义的。
定义集合:VAR 集合名:SET OF 数据类型;
这里需要注意的是:集合只能定义成整数(byte)、布尔型或CHAR型的。
如:VAR S:SET OF byte;
其作用是定义了一个整数型的集合S。
集合的赋值:集合的值实际上应该是一些数据的总和。一个集合的值(元素)是用中括号“[]”括起来的。如:
S:=[];是把S赋成一个空集合。
S:=[1,2,4];是把S赋成一个有三个元素的集合。
集合的运算:集合的并、交、差运算及关系运算。
1、 并:用运算符“+”:即把两个集合的元素合并。如:S:=[1,2]+[4,5];是把S赋值成四个元素。
2、 交:用运算符“*”:即取两个集合的相同元素。如:S:=[1,2,3]*[3,4,5];这时S的值被赋成了一个元素[3]。
3、 差:用运算符“-”:即取属于前一集合但不属于后一集合的元素。如:S:=[1,2,3]-[2,5,6];这时S的值被赋成了[1,3]。
4、 关系运算:这是在PASCAL语言中集合概念最重要的部分,是用来判断集合之间或集合与元素之间关系的运算。有以下几种:
A、=:判断两个集合的元素是否完全相同;
B、<>:判断两个集合是否不相等;
C、>=:包含;
D、<=:包含于;
E、IN:存在于。即用来判断一个元素是否存在于一个集合中。
第三节、自定义数据类型
PASCAL语言不仅直接提供大量的可直接使用的数据类型,还提供了功能强大的扩展自定义功能,用户可以自己定义适合自己程序中使用的数据类型。这种自定义数据类型同样是在程序头部加以说明,引导字是TYPE,定义好类型后,就可能把常/变量定义成这种类型了。这样的自定义数据类型有两种定义方式,分别是:枚举类型、子界类型。
一、 枚举类型
日常生活中的一个星期中的每天的名称:SUNDAY、MONDAY等,颜色的名称:RED、BLUE等,如果我们的PASCAL程序中要使用这些数据的话是很不方便的,所以我们可以使用自定义枚举类型来使它运用起来更加方便。
定义语法如下:TYPE 类型名=(标志符);
如:TYPE COLOR=(RED,BLUE,GREEN,YELLOW,BLACK,WHITE);
WEEKDAY=(SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY);
MONTH=(JAN,FEB,MAR,APR,MAY,JUN,AUG,SEP,OCT,NOV,DEC);
这样,我们就能在定义常/变量时把常/变量定义成这些类型。如:
VAR C:COLOR;
W:WEEKDAY;
M,N:MONTH;
在程序中,我们使用上述四个变量时,它们的值只能是对应的类型中的值。如:C这个变量的值就只能是:RED,BLUE,GREEN,YELLOW,BLACK,WHITE。
注意:枚举类型的数据是有序的。即可用函数:PRED()前趋;SUCC()后续。这两个函数的用法我们将在下面介绍。
枚举类型数据的运算:
1、 赋值:如:C:=BLUE;
W:=FRIDAY;
2、 判断:如:BLUE>GREEN的值为TRUE;
3、 函数:PRED()、SUCC()、ORD()。因为枚举类型是有序的,所以可以使用上述三个和序数有关的函数。如:
A、 SUCC(FRIDAY)的值为SATURDAY;即FRIDAY之后的一个值。
B、 PRED(YELLOW)的值为GREEN。即YELLOW之前的一个值。
C、 ORD(BLUE)的值为2;即BLUE在其对应的枚举类型中排在第二位。
二、子界类型
子界类型也是自定义数据类型中的一种。在上一节的枚举类型中我们知道,枚举类型是把一种数据类型所有的值都列举出来。而当需要自定义的类型是一序列连续的数据,并且数量很大时,枚举类型就不适合了,这时,我们就会采用子界类型。子界类型,顾名思义,就是当数据是连续的时,可以指定其上界及下界来定义。定义方法与枚举类型相似。
TYPE 类型名称=上界..下界;
如:TYPE YEAR=1900..2000;是定义一个名为YEAR的数据类型,其值可取为1900—2000。
再如:TYPE NUMBER=1..9;
CHARACTER=’a’..’z’;
上述语句定义了两个子界类型的变量,第一个NUMBER的取值为1至9;第二个CHARACTER的取值为小写字母‘a’至‘z’。
三、记录类型
记录型数据类型是PASCAL语言中做搜索问题中一定要用到的数据类型,所以,它在PASCAL语言中占着非常重要的地位。学过数据库管理软件的人都知道,在数据库文件中,有一个非常重要的概念—记录,例如:一个人的各门成绩,一个人的各种信息(姓名、性别等等),我们都把它们存放成一条记录而给予一个统一的名称。
1、 记录说明:记录类型和枚举类型一样,都要在程序头部用TYPE引导说明。语法如下:
TYPE 类型名称=RECORD
域变量1:基类型;
域变量2:基类型;
…………
END;
然后在常/变量说明中就要以用这种类型了。在程序中使用必须指定变量名与域名。
[例6、2]编一程序,用来记录20个学生的姓名、年级、班级、性别、语文成绩、数学成绩、总分,平均分。
Type student=record
Name:string;
Grade,class,chinese,mathe,sum:integer;
Average:real;
Male:boolean;
End;
Var s:array[1..20] of student;
I,j:integer;
Begin
For I:=1 to 20 do begin
Write(‘please input the student’s name,grade,class,male,chinese,mathe);
Readln(s[I].name);
Readln(s[I].grade);
Readln(s[I].class);
Readln(s[I].male);
Readln(s[I].chinese);
Readln(s[I].mathe);
S[I].sum:=s[I].chinese+s[I].mathe;
S[I].average:=s[i].sum/2
End;
…………
{如果程序要求打印或排序,只需在此增加这些功能语句}
end.
第四节、字符串
在PASCAL语言中,字符串的处理是非常方便的,在定义字符串时,我们不仅可以定义成CHAR型(单个字符);STRING型(任意个字符);STRING[N]型(指定只有N个字符)。在后两种类型中,我们都可以使用:变量名[I],来指定字符串中的第I字符,以便得到它的值或对其赋值。而且,我们还可以使用如下函数对字符串进行各种操作:
1、 CHR(N):返回N(ASCII码)对应的字符。如:CHR(66)的值是’b’;
2、 UPCASE(C):把字符串全部转成大写字母。
3、 CONCAT(S1,S2):把两个字符串相加,如:CONCAT(‘ABC’,‘123’)的结果是‘ABC123’;
4、 COPY(S,M,N):这是很有用的一个函数,它的作用是取字符串S第M个字符开始的N个字符作为一个新的子串。如:COPY(‘ABCDE’,3,2)的值是‘CD’;
5、 LENGTH(S):求字符串S的长度。如:LENGTH(‘ABCD’)的值是4;
6、 DELETE(S,M,N):与COPY的功能正好相反,作用是把字符串S的第M个字符开始的N个字符删除掉。如DELETE(‘ABCDEF’,3,2)的结果是‘ABEF’;
7、 INSERT(S1,S2,N):把字符串S1插入到字符串S2中,插在S2的第N个字符。如:INSERT(‘ABCD’,‘12345’,2)的结果是:‘1ABCD2345’。
8、 POS(S1,S2):这是一个非常有用的函数,其作用是判断S1是否是S2的子串,返回结果是:(1)如果是子串,只返回S1在S2中的起始位置;(2)如果不是子串,则返回0。如:POS(‘123’,‘ABCDEF’)的值为0;POS(‘AB’,‘BABCD’)的值为2;
另外,我们还可以使用如下几个过程:
1、 STR(N,S):这是一个过程,作用是把N这个数值转化为S这个字符串。如:STR(123,S),作用是把S的值赋成了‘123’;
2、 VAL(S,N,CODE):这也是一个过程,作用是把S这个字符串转化为N这个数值,并且同时返回CODE这个错误代码(整数型)。如:VAL(‘135’,N,C);作用是把N的值赋成了135这个数值,而且返回C这个错误代码。为什么会有错误代码呢?大家看这个语句是否错误,错在哪里:VAL(‘12ABC’,M,C);
[例6、3]把26个英语字母正向、逆向打印出来。
Const s:string[26]=’abcdefghijklmnopqrstuvwxyz’;
Var t:string[26];
I:integer;
Begin
t:=’ ‘; {共26个空格}
For I:=1 to 26 do begin
T[I]:=s[27-I];
End;
Writeln(s);
Writeln(t);
End.
[例6、4]找出所有的四位回文数:(回文数就是一个数从左往右读与从右往左读都是同一个数)
var s:string[4];
n:integer;
begin
for n:=1000 to 9999 do begin
str(n,s);
if (s[1]=s[4]) and (s[2]=s[3]) then write(n:6);
end;
end.
或者用如下程序:
var n:integer;
s,t:string;
begin
for n:=10 to 99 do begin
str(n,s);
t:=s+s[2]+s[1];
write(s:6);
end;
end.
上述两个程序,哪个快,哪个慢?