p25 集合

p25集合

一、集合的概念

集合是由一些同类型的对象汇集在一起形成的,从这点上讲集合跟数组是相同的,不同的是集合中的元素的个数是可变的,而且集合只作为一个整体来使用,不能单独使用集合中的元素,Pascal语言中的集合类型,同数学中集合的概念一样。具体地说,一个集合就是由同一种有序类型的一组数据元素所组成的,这一种有序类型称为该集合的基类型。

集合一般用一对方括号表示,如:[red,black,white,blue,green,yellow]

其中,red,black,white,blue,green,yellow称为集合的元素。在集合中,各元素之间用逗号隔开。在一个集合中可以没有任何元素,这样的集合称为空集合,用[ ]表示。

在使用集合时要注意以下几点:

(1) 集合的值与方括号内元素出现的次序无关。如[1,2,3,4] [1,2,4,3]是两个相等的集合;

(2) 在集合中,同一元素的重复出现对集合的值没有影响。如[1,2,3,1,1,2][1,2,3]也是两个相等的集合;

(3) 在集合中,如果元素的值是连续的,则可以用子界类型来表示。如[1,2,3,4,5,8,9,10,15,21,22,23,24],这个集合可以表示成[1..5,8..10,15,21..24];

(4) 集合的基类型可以是任何顺序类型,包括整型、字符型、枚举型、子界型,但不能为实型或其他构造类型。

(5) 每个元素均可用基类型所允许的表达式来表示。如:[1+10,4*2,3..6]

二、集合类型的定义格式为:

type 标识符=set of 基类型;

 例如:type num1=set of 1..10;

           num2=set of integer;

               c1=set of ‘A’..’Z’;

               c2=set of char;

           weekday=(sun,mon,tue,wed,thur,fri,sat);

           colors=(red,black,white,blue,green,yellow);

           fruits=(orange,banana,apple);

           c3=set of weekday;

           c4=set of colors;

           c5=set of fruits;

这样就定义了7个集合,num1是数字1到数字10的数字集合类型,num2是整数集合类型,c1是字符’A’到字符’Z’的字符集合类型,c2是所有字符的集合类型,c3,c4,c5都是枚举集合类型,它们分别表示一周的7天、6种颜色和4种水果。

有了以上的集合类型定义后,我们就可以定义集合型变量了。如:

var n:num1;

   ch:c1;

也可以把集合类型的定义和集合变量的定义合并在一起。如:

var n:set of 1..10;

   ch:set of ‘A’..’Z’;

当一个集合变量允许包含有n个元素时,不考虑有重复元素的情况,则所构成的集合有多少种可能?不难算出应该是2n种。

例如:type numset=set of 1..3;

      var n:numset;

则集合n的值有8种可能,分别为:[ ],[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]

三、集合的赋值

对集合变量的赋值只能通过赋值语句来完成。而不能通过输入语句(readreadln)来进行。例如,假设在程序的说明部分已包含以下一行:

var ch1,ch2:set of ‘A’..’Z’;

则,在程序的执行部分,只能通过赋值语句对ch1,ch2赋值,如:

ch1:=[ ];ch2:=[‘A’..’D’];

而不能用read(ch1,ch2);

另外还要注意,赋值号的右边必须用[‘A’..’D’],而不能写成ch2:=’A’..’D’;因为赋值号的左边是集合型变量,根据赋值相容原理,赋值号右边也必须是一个集合(或集合表达式)。

四、集合运算的实现

1集合之间的并、交、差运算

假设有AB两个集合,A=[1345]B=[4567],则AB可以进行三种集合运算,见下表

运算符

运算名称

表示形式

运算方法

运算结果

+

A+B

取两个集合中不重复的所有元素。

[1,3,4,5,6,7]

*

A*B

取两个集合中的相同元素

[4,5]

-

A-B

取在集合A中但又不在集合B中的所有元素。

[1,3]

例如:

[1,2,4]+[3]=[1,2,3,4];  [2,3,4]*[1,2,3]=[2,3];  [1,2,3,4]-[2]=[1,3,4]

集合之间也可以进行关系运算,具体的使用方法如下表所示:

关系运算符

关系运算名称

关系运算的含义

=

相同

检查两个集合所包含的元素相同

<>

不相同

检查两个集合不相等

<=

包含于

检查第一个集合中的元素是否都在第二个集合中出现

>=

包含

检查第一个集合中的元素是否包含第二个集合中的所有元素

in

属于

检查集合基类型的一个元素是否属于集合

注意:并、交、差运算都是针对两个集合的,旦运算结果也是一个集合。另外,集合的并(+)、交(*)、差(-)运算形式上与算术运算的加(+)、乘(*)、减(-)是一样的,但含义却完全不同。

2.集合之间的关系运算

两个集合之间可以进行相等或不相等、包含或被包含的关系运算,关系运算的结果均为布尔值。假设有AB两个集合,A=[1,3,4,5],B=[1,3,4],则这四种关系运算的含义如下表:

运算符

名称

表示形式

定义

运算结果

=

相等

A=B

测试两个集合是否相等

false

<>

不相等

A<>B

测试两个集合是否不相等

true

<=

包含于

A<=B

测试集合A中的元素是否都包含于集合B

false

>=

包含

A>=B

测试集合A是否包含集合B中的所有元素

true

3in运算

在程序设计过程中,我们经常需要检查一个元素是否在指定的集合中,从而对这个集合做进一步的操作,如“添加一个元素到集合中”或“删除集合中的一个元素”。pascal为我们提供了“属于集合”运算符——in,它是用来判断元素与集合的关系的,运算结果也是布尔型。

举例来说,假设集合a=[1..5],xinteger,要求判断x是否在集合a中,若在则删除a中的x这个元素,若不在则把x在个元素添加到集合a中,程序段如下:

if x in a then a:=a-[x]

else a:=a+[x];

集合变量的输出也不能直接用writewriteln语句,往往也是通过in运算。例如,假设集合a=[1,3,5,7,9,11,13,15,17,19],xinteger,要求输出20之内的奇数,程序段如下:

for x:=1 to 20 do

   if x in a then write(x:3);

 

下面是一段关于集合输入输出的参考程序:

Type

  Weekday=(Sunday,Monday,tusday,Wednesday,Thursday,Friday,saturday);

  Dayset=set of weekday;

Const

  Daynames:array[weekday] of string;

Var

  Workday:dayset;

  Day:weekday;

  Separator:char;

Begin

 ……….

  Write(‘[’);

  Separator:=’ ‘;

  For day:=Sunday to Saturday do

If day in workday

  Then 

    Begin

      Write(separator,daynames[day]);

      Separator:=’,’;

    End;

  Write(‘]’)

End.

输入一串字符,以“?”结束,组成元音字母集合、辅音字母集合,然后输出两集合元素及其元素个数。

Program aa;

Var

  S1,s2:set of ‘a’..’z’;

  N1,n2:integer;

  Ch:char;

Begin

  S1:=[ ];

  S2:=[ ];

  N1:=0;

  N2:=0;

  Read(ch);

  While ch<>’?’  do

Begin

  If ch in[‘a’..’z’]

    Then if ch in [‘a’,’e’,’i’,’o’,’u’]

       Then s1:=s1+[ch]

       Else s2:=s2+[ch];

  Read(ch);

End;

  For ch:=’a’ to ‘z’ do

If ch in s1

  Then

    Begin

      Write(ch);

      N1:=n1+1;

    End;

Writeln;

Writeln(‘n1=’,n1);

For ch:=’a’ to ‘z’ do

  If ch in s2

    Then

      Begin

        Write(ch);

        N2:=n2+1;

      End;

Writeln;

Writeln(‘n2=’,n2);

End.

2调用随机函数产生10个互不相同的随机整数(0≦x≦40),放入集合中并一起输出(5个一行)

程序代码如下:

program aa;

  var

a:set of  0..40;

i,m,n:integer;

  begin

a:=[ ];n:=0;

randomize;    {初始化随机数发生器}

repeat

  m:=random(41);  {随机数发生器}

  if not (m in a) then begin a:=a+[m];

                      n:=n+1;

                  end;

  until n=10;

  n:=0;

  for i:=0 to 40 do

    if i in a then begin write(i:4);

                    n:=n+1;

                    if (n mod 5)=0 then writeln

               end;

 end.

注意:在使用Random之前需要使用Randomize语句进行随机数种子的初始化。

  例如:

  var

  a,i,,j:integer;

  begin

  {RANDOMIZE;}

  for j:=1 to 2 do 

  begin

  for i:=1 to 10 do

  begin

  a:=random(1000);

  writeln(a);

  end;

  writeln;

  end;

  end.

  这两组数据输出的是一样的结果,如果在程序前加上RANDOMIZE(即把大括号去掉)再运行程序,输出数据就不一样了

RANDOM产生的是伪随机数或者说是用一种复杂的方法计算得到的序列值,因此每次运算时需要一个不同的种子值。种子值不同,得到的序列值也不同。因此也就是真正的随机数了。这也正是RANDOMIZE随机初始化的作用。

3、用筛选法求n以内的所有素数(包括n,输出时5个一行)

问题分析:筛法是一种高效地求素数的方法,它是由希腊著名数学家埃拉托色尼首先提出的,具体算法如下:

假设用集合变量sieve表示筛子,用集合变量primes存放结果(n以内的所有素数)

① 初始化:将所有侯选数放入筛中,即sieve:=[2..n],同时给primes:=[ ];

② 找出筛中的最小数nextnext必定为素数;{请同学们思考为什么?}

③ 将next这个数存入primes中,同时将它的所有倍数从sieve筛去;

④ 重复②~③,直到筛空(sieve=[ ])。

程序代码如下:

program aa;

const n=100;

var sieve,primes:set of 1..n;

next,j:integer;

begin

  sieve:=[2..n];

  primes:=[ ];

  next:=2;

  repeat

    while not(next in sieve) do next:=next+1;

    primes:=primes+[next];

    j:=next;

    while j<=n do

      begin

        sieve:=sieve-[j];

        j:=j+next;

      end;

    until sieve=[ ];

    j:=0;

    for next:=2 to n do

      if (next in primes) then

        begin

          write(next:4);

          j:=j+1;

          if (j mod 5=0) then writeln;

        end;

      writeln;

end.

程序运行输出的结果:

2  3   5   7   11

13 17  19  23  29

31 37  41  43  47

53 59  61  67  71

73 79  83  89  97  

 

转载于:https://www.cnblogs.com/lj_cherish/archive/2010/10/11/1848212.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值