§6 集合与记录类型
§6.1 集合类型
§6.1.1 集合类型的定义
集合是同类型对象的一个汇集,它是指同类型对象汇集在一起构成的数据结构。集合的每一个对象称为集合的元素。集合元素必须是有序简单数据类型,集合元素的类型称为集合的基类型。集合的一般形式为:
TYPE <类型标识符> = set of <基类型>;
基类型可以是整型、字符型、布尔型、枚举型、子界型等,但不能是实型或结构类型。 例如:
TYPE letter = set of ‘A’.. ‘Z’; var ch1, ch2 : letter; 也可以直接写成:
var ch1, ch2 : set of ‘A’.. ‘Z’;
在Pascal中集合是用一组括在方括号中的元素来表示,元素之间用逗号分隔。如: [A, B , C , D] 是四个枚举量的集合
[ 1 .. 20 ] 表示1到20的所有整数的集合 [ ‘0’ ] 是单元素集 [ ] 表示空集
一个集合类型变量的取值,可以是基类型中所有元素按不同的组合而构成的子集。例如,上面说明变量ch1的类型是letter,它可以是下列的组合:
[‘A’ .. ‘Z’] 全集
[‘A’, ‘B’, ‘Q’] 任一子集 [‘A’ .. ‘C’ , ‘X’ ..‘Z’ ] [‘A’ ] 单元素集 [ ] 空集 空集与所有的集合类型都兼容。 §6.1.2 集合类型的运算
ch1:=[ [‘A’ .. ‘C’]];
是合法的集合赋值。对集合除可以进行赋值运算外,还可以进行以下运算:
·交(*)运算:两集合之交 S1*S2 为一集合,所得元素由S1、S2中相同的元素组成。 如: [ 0..7 ] * [ 0..4 ] = [ 0..4 ]
·并(+)运算:两集合之并 S1+S2 为一集合,所得元素由S1、S2中所有相同的元素组
成。如: [ 0..7 ] + [ 0..4 ] = [ 0..7 ]
[ 0 , 1 ] + [ 1 , 4 , 6 ] = [ 0 , 1 , 4 , 6 ]
1 / 11
·差(-)运算:两集合之差 S1-S2 为一集合,所得元素由只存在于S1而不在S2的那
些元素组成。如: [ 0..7 ] - [ 0..4 ] = [ 5..7 ] ·比较运算: 集合可进行“=”、“>=”、“<=”、“<>”等比较运算: 等于“=”—— S1=S2,若S1与S2中所有元素均相同,结果为true,否则为false。 如: [ 0..4 ] = [ 0..4 ] 结果为true [ 0..7 ] = [ 0..4 ] 结果为false
不等于“<>”——S1<>S2,S1与S2中至少有一个元素不同,
如: [ 0..7 ] <> [ 0..4 ] 结果为true
[ 0..4 ] <> [ 0..4 ] 结果为false 包含“>=”——S1>=S2 表示S2是S1的子集。 被包含“<=”——S1<=S2 表示S1是S2的子集。
如: [ 0..7 ] >= [ 0..4 ] 结果为true
[ 0..7 ] <= [ 0..4 ] 结果为false [ ] <= [ 0..4 ] 结果为true ·检查(in)运算:用来检查某一元素是否属于某一集合。如: 1 in [ 0 .. 4 ] 结果为true 5 in [ ] 结果为false
‘A’ in [‘A’ ..‘Z’ ] 结果为true §6.1.3 集合类型的表达式
集合表达式是由集合常数、集合变量、集合构造符和集合运算符组成。如: k := 5;
ch2 := [ 1, 2 , 3 , 4 ] + [ k ];
运行之后,ch2中就会有5个元素:1、2、3、4、5。
注意:[ 1..5 ] [ 1, 2, 3, 4, 5 ]两种表达式是等价的。 .........与......................集合运算相当快,在程序中常用集合表达式来描述复杂的测试。 例如,条件表达式:
(ch=’T’) or (ch=’u’) or (ch=’R’) or (ch=’B’) 可用集合表达式表示为:
ch in [‘T’, ‘u’, ‘R’, ‘B’ ] 又如: if (ch>=20) and (ch<=50) then <语句> 可写成: if ch in [ 20..50 ] then <语句> §6.1.4 注意问题
集合类型是一种使用简单,节省内存而又运算速度快的数据类型,在解决某些问题时,它能使程序编写简明清晰,节省内存而又节省运行时间。但是使用集合时必须注意以下几点:
① Pascal规定集合的元素个数不超过256个。当实际问题所需的元素个数大于256时,
可采用布尔数组代替集合类型。
所以 var i : set of integer; 的说明是错误的,因为它的元素个数超过256
2 / 11
个。
②集合类型变量不能进行算术运算,也不允许用读/写语句直接输入/输出集合。所以集合
的建立要通过赋值语句实现,或先初始化一个集合,然后通过并(+)运算向集合中逐步加入各个元素;集合的输出也必须间接地转换,如集合中的元素是数字或字母,可通过序数值的转换关系输出对应的字符。 ③集合的元素是无序的,所以 ord , pred 和succ 函数不能用于集合类型的变量。
【例1】用集合方法编程,实现把100以内的全部素数找出来,然后把求得的每十个素数排成
一行,形成素数表。
算法分析:用筛法求素数。
第一步,定义一个集合类型,如sss,它包含99个元素,从2到100;
第二步,定义两个集合变量,如筛集合 s 和素数集合 p,它们是sss类型的变量; 第三步,按筛法找出全部素数; 第四步,间接输出素数表。 算法求精如下:
① 把2到100逐步放入筛中,建立筛集合s; ② 选定筛中最小的素数——2;
③ 把选定的素数放入素数集合P中;
④ 检查筛集合s,从中删去选定素数和它的所有倍数;
⑤ 重复步骤2、3、4,直到筛集合s变成空集,素数集合P完全建立; ⑥ 间接输出集合P中的元素,且每10个一行。 程序清单:
program erato; const n=100;
type sss=set of 2..n; var s, p : sss;
next , j : integer;
Begin
s:=[2..n]; {初始准备} p:=[ ]; next:=2;
repeat {建立素数表}
while not (next in s) do next:=next+1; p:=p+[next]; j:=next;
while j<=n do begin {去掉选定素数的倍数} s:=s-[j]; j:=j+next; end; {while} until s=[ ];
3 / 11
j:=0;
for next:=2 to n do {输出素数集合元素}
if next in p then begin
write(next : 5); j:=j+1;
if j=10 then {每10个素数为一行}
begin
writeln; j:=0;
end; end; {if} End.
§6.2 记录类型
记录类型数据是由固定数量,具有不同类型的成份组成。这种数据在实际问题中常遇到,如描述学生姓名、性别、年龄、班级和各科成绩的档案登记表。这种数据用数组类型是非常烦琐的,可以利用Pascal提供的记录类型。 §6.2.1 记录类型的数据
记录是由固定数量的字段(又称域)的元素所组成的一种结构,各个字段可以具有各种不同的数据类型,每个字段都有一个名称即字段标识符。
记录类型定义的一般形式:
TYPE <类型标识符> = RECORD
<字段名1> : <类型1>; ┆ ┆
<字段名n> : <类型n>; END;
记录中描述对象的字段表,包括了记录的固定部分和变体部分;记录的固定部分由字段名和类型说明部分,记录的变体部分在本节的最后介绍。
下面介绍如何描述记录的数据,例如: type date = record
year : 1900 .. 2500;
month : (JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,
DEC);
day : 1..31;
end;
var date1, date2 : date;
对记录类型变量的访问,不同于数组那样通过下标来访问其成份,而是通过记录变量名,句号(.),字段名 来访问记录中的成份,称为记录的点记法,其形式为:
<记录变量名>.<字段名> := <数据项>;
4 / 11
例如: date1.year := 1937; date1.month := JUL; date1.day:=7;
如果记录的某个字段是字符型数组,如student.name字段是一个由20字符组成的字符型数组,则可用循环语句读入字符:
for i:=1 to 20 do read (student.name[ i ]);
· 记录类型与数组类型相似,允许在同类型的两个记录之间进行整体赋值。
如: date2 := date1;
· 记录可以嵌套,即记录中的字段的类型也可以是记录,嵌套的记录类型是有层次的数据类
型。在同一层的标识符不能同名,但不同层的字段名可以同名。 例如: var r : integer;
s : record r : real;
s : record
r : char;
s : boolean; end; end;
对于层次记录的引用必须采用自顶向下的完全路径,如: var worker = record
age : 15..70; birth : record
year : 1900..2200; month : 1..12; end; end;
引用记录变量worker的域,表示出生年,应写成: worker . birth . year
【例2】设学生成绩登记表有下列项目:学号、姓名、年龄、班级、数学、物理、政治、英语、
总分。现对学生成绩进行统计,算出各科的总分和平均分。
程序清单:
program stu; const n=60;
type student=record
no : integer;
name : string[16];
5 / 11