just do it

PASCAL语言 基础教程二

第五章、选择结构

本章讨论程序的分支结构,其主要知识是布尔运算(逻辑运算)。

第一节、布尔运算(逻辑运算)

要判断“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

ˇ

语句序列2

ˇ

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语句,它能使程序有很多个分支。其效果如下图:

表达式
语句序列1
语句序列2
case
……

其格式为:

语句序列N

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

循环体
布尔表达式
循环体
true
false
布尔表达式
false
true

 

从上述框图中可以看出,要使用循环语句时,必须要确定循环体及条件(布尔表达式)两个重要因素,亦即首要考虑的是:我要重复执行哪些语句,我要重复到什么时候为止!

[例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.

上述两个程序,哪个快,哪个慢?

点赞