抽象数据类型Word格式文档下载.docx
《抽象数据类型Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《抽象数据类型Word格式文档下载.docx(11页珍藏版)》请在冰豆网上搜索。
01
万明华
男
1962.03.20
处长
02
赵宁
1968.06.14
科长
教材科
03
张利
女
1964.12.07
考务科
04
赵书芳
1972.08.05
主任
办公室
05
刘永年
1959.08.15
科员
06
王明理
1975.04.01
07
王敏
1972.06.28
08
张才
1967.03.17
09
马立仁
1975.10.12
10
邢怀常
1976.07.05
【例1.1】一种数据结构的二元组表示为set=(K,R),其中
K={01,02,03,04,05,06,07,08,09,10}
R={}
在数据结构set中,只存在有元素的集合,不存在有关系,或者说关系为空。
这表明只考虑表中的每条记录,不考虑它们之间的任何关系。
把具有此种特点的数据结构称为集合结构。
集合结构中的元素可以任意排列,无任何次序。
【例1.2】一种数据结构的二元组表示为linearity=(K,R),其中
R={<
05,01>
<
01,03>
03,08>
08,02>
02,07>
07,04>
<
04,06>
06,09>
09,10>
}
对应的图形表示如图1.1所示。
图1.1数据的线性结构示意图
结合表1.1,细心的读者不难看出:
R是按职员年龄从大到小排列的关系。
在数据结构linearity中,数据元素之间是有序的,每个数据元素有且仅有一个直接前驱元素(除结构中第一个元素05外),有且仅有一个直接后继元素(除结构中最后一个元素10外)。
这种数据结构的特点是数据元素之间的1对1(1∶1)联系,即线性关系。
我们把具有这种特点的数据结构叫做线性结构。
【例1.3】一种数据结构的二元组表示为tree=(K,R),其中
R={<
01,02>
01,04>
02,05>
02,06>
03,07>
03,09>
04,10>
对应的图形表示如图1.2所示。
图1.2数据的树结构示意图
R是职员之间领导与被领导的关系。
图1.2像倒着画的一棵树,在这棵树中,最上面的一个没有前驱只有后继的结点叫做树根结点,最下面一层的只有前驱没有后继的结点叫做树叶结点,除树根和树叶之外的结点叫做树枝结点。
在一棵树中,每个结点有且只有一个前驱结点(除树根结点外),但可以有任意多个后继结点(树叶结点可看作为含0个后继结点)。
这种数据结构的特点是数据元素之间的1对N(1∶N)联系(N≥0),即层次关系,我们把具有这种特点的数据结构叫做树结构,简称树。
【例1.4】一种数据结构的二元组表示为graph=(K,R),其中
K={01,02,03,04,05,06,07}
02,01>
04,01>
02,03>
03,02>
06,02>
07,02>
07,03>
06,04>
05,07>
07,05>
对应的图形表示如图1.3所示。
从图1.3可以看出,R是K上的对称关系。
为了简化起见,我们把〈x,y〉和〈y,x〉这两个对称序偶用一个无序对(x,y)或(y,x)来代替;
在示意图中,我们把x结点和y结点之间两条相反的有向边用一条无向边来代替。
这样R关系可改写为:
R={(01,02),(01,04),(02,03),(02,06),(02,07),
(03,07),(04,06),(05,07)}
对应的图形表示如图1.4所示。
如果说R中每个序偶里的两个元素所代表的职员是好友的话,那么R关系就是人员之间的好友关系。
图1.3数据的图结构示意图图1.4图1.3的等价表示
从图1.3或1.4可以看出,结点之间的联系是M对N(M∶N)联系(M≥0,N≥0),即网状关系。
也就是说,每个结点可以有任意多个前驱结点和任意多个后继结点。
我们把具有这种特点的数据结构叫做图结构,简称图。
从图结构、树结构和线性结构的定义可知,树结构是图结构的特殊情况(即M=1的情况),线性结构是树结构的特殊情况(即N=1的情况)。
为了区别于线性结构,我们把树结构和图结构统称为非线性结构。
集合结构是整个数据结构中的一种特殊情况,其元素之间不存在任何关系。
【例1.5】一种数据结构的二元组表示为B=(K,R),其中
K={k1,k2,k3,k4,k5,k6}
R={R1,R2}
R1={<
k3,k2>
k3,k5>
k2,k1>
k5,k4>
k5,k6>
R2={<
k1,k2>
k2,k3>
k3,k4>
k4,k5>
若用实线表示关系R1,虚线表示关系R2,则对应的图形表示如图1.5所示。
图1.5带有两个关系的一种数据结构示意图
从图1.5可以看出:
数据结构B是图结构。
但是,若只考虑关系R1则为树结构,若只考虑关系R2则为线性结构。
下面简要讨论数据的存储结构。
存储数据不仅要存储数据中的每个数据元素,而且要存储元素之间的逻辑关系。
具体地说,若数据是集合结构,则只需要存储所有数据元素,不需要存储它们之间的任何关系;
若数据是线性结构、树结构或图结构,则除了要存储所有数据元素外,还要相应存储元素之间的线性关系、层次关系或网状关系。
数据的存储结构分为顺序、链接、索引和散列4种。
顺序存储对应一块连续的存储空间,该空间的大小要大于等于存储所有元素需占有的存储空间的大小,存储元素之间的联系(即逻辑结构)通常不需要附加空间,而是通过元素下标之间的对应关系反映出来,只要简单的计算就可以得到一个元素的前驱或后继元素的下标。
顺序存储空间一般需要通过定义数组类型和数组对象来实现。
在链接存储结构中,元素之间的逻辑关系通过存储结点之间的链接关系反映出来,每个存储结点对应存储一个元素,同时存储该元素的前驱和后继元素所在结点的存储位置,或者说同时存储指向其前驱元素结点和后继元素结点的指针,通过这些指针能够直接访问到其前驱元素和后继元素。
链接存储空间通过定义元素的存储结点类型和对象来实现,所有存储结点可以占用连续的存储空间(即数组空间),也可以占用不连续的存储空间,此空间是由动态分配的每个结点的空间形成的。
索引存储是首先把所有数据元素按照一定的函数关系划分成若干个子表,每个子表对应一个索引项,然后采用一种存储结构存储所有子表的索引项和采用另一种存储结构存储所有子表中的元素。
如存储汉字字典时,需要采用索引存储,首先按偏旁部首划分所存汉字为若干子表,得到偏旁部首表,对于每个部首再按所属汉字的笔画多少划分子表,得到检字表,检字表中的每个汉字对应汉字解释表(即字典主体)中的一个条目;
然后再分别存储部首表、检字表和汉字解释表。
这里检字表是汉字解释表的索引,而偏旁部首表又是检字表的索引,它是汉字解释表的二级索引。
当存储的数据量很大时,通常都需要采用索引存储,并且时常使用多级索引。
在索引存储中,各级索引表和主表(即数据元素表)通常都以文件的形式保存在外存磁盘上,访问任一数据元素时,都要根据该数据元素的特征依次访问各级索引表和最后访问主表,存取外存的次数至少等于建立索引的级数加1。
散列存储方法是按照数据元素的关键字通过一种函数变换直接得到该元素存储地址的方法,该存储地址为相应数组空间中的下标位置。
用于散列存储所有数据元素的相应数组空间称为散列表。
通过定义用于计算散列存储地址的函数和定义存储数据元素的散列表能够实现散列存储结构。
以上简要叙述了数据结构的有关概念,在以后的各专题中将会做深入和具体的讨论。
1.2抽象数据类型
抽象数据类型(AbstractDataType,ADT)由一种数据结构和在该数据结构上的一组操作所组成。
抽象数据类型包含一般数据类型的概念,但含义比一般数据类型更广、更抽象。
一般数据类型由具体语言系统内部定义,直接提供给编程者定义用户数据,因此称它们为预定义数据类型。
抽象数据类型通常由编程者定义,包括定义它所使用的数据、数据结构以及所进行的操作。
在定义抽象数据类型中的数据部分(含数据结构在内)和操作部分时,可以只定义数据的逻辑结构和操作说明,不考虑具体的存储结构和操作的具体实现,这样能够为用户提供一个简明的使用接口,然后再另外给出具体的存储结构和操作的具体实现,使得操作声明与实现分开,从而符合面向对象的程序设计思想。
抽象数据类型在C++语言中是通过类类型来描述的,其数据部分通常定义为类的私有或保护的数据成员,它只允许该类或派生类直接使用,操作部分通常定义为类的公共的成员函数,它既可以提供给该类或派生类使用也可以提供给外部定义的类和函数使用。
在本书中,为了便于叙述和分析数据结构和算法,使读者容易理解和接受,所以在实现所定义的抽象数据类型时,把数据部分用一种已知的数据类型(如结构或数组等)来实现,把操作部分中的每个操作用普通函数来实现,这样能够同读者熟悉的C语言、C++语言,甚至其他计算机语言很好地兼容起来。
一种抽象数据类型的定义将采用如下书写格式:
ADT<
抽象数据类型名>
is
Data:
数据描述>
Operations:
操作声明>
end<
【例1.6】假定把矩形定义为一种抽象数据类型,其数据部分包括矩形的长度和宽度,操作部分包括初始化矩形的尺寸、求矩形的周长和求矩形的面积。
假定该抽象数据类型名用RECtangle(矩形)表示,定义矩形长度和宽度的数据用length和width表示,并假定其类型为浮点(float)型,初始化矩形数据的函数名用InitRectangle表示,求矩形周长的函数名用Circumference(周长)表示,求矩形面积的函数名用Area(面积)表示,则矩形的ADT(抽象数据类型)描述如下:
ADTRECtangleis
一个矩形r,其长度和宽度分别用length和width表示
//初始化矩形r的长度和宽度值为len和wid
voidInitRectangle(Rectangle&
r,floatlen,floatwid);
//求矩形r的周长并返回
floatCircumference(Rectangle&
r);
//求矩形r的面积并返回
floatArea(Rectangle&
endRECtangle
这里假定数据部分的矩形r是类型名为Rectangle的一个结构对象,该类型的具体定义如下:
structRectangle{
floatlength,width;
};
下面给出每个操作的具体实现。
(1)初始化矩形尺寸
r,floatlen,floatwid){
r.length=len;
//把len值赋给r的length域
r.width=wid;
//把wid值赋给r的width域
}
该函数把两个值参len和wid的值分别赋给引用参数r的length域和width域,实现对一个矩形r的初始化。
(2)求矩形周长
r){
return2*(r.length+r.width);
(3)求矩形面积
returnr.length*r.width;
求矩形周长和面积的函数分别使用一个矩形引用参数,当然也可以改为值参。
【例1.7】把二次多项式ax2+bx+c设计成一种抽象数据类型,假定起名为QUAdratic,该类型的数据部分为三个系数项a,b和c,操作部分为:
(1)初始化a,b和c的值,假定它们的默认值均为0;
(2)做两个多项式加法,返回它们的和;
(3)根据给定x的值计算多项式的值并返回;
(4)计算方程ax2+bx+c=0的两个实数根,对于有实根、无实根和不是二次方程(即a==0)这三种情况都要返回不同的整数值,以便返回后做不同的处理;
(5)按照ax**2+bx+c的格式输出二次多项式,在输出时要注意去掉系数为0的项,并且当b和c的值为负时,其前不能出现加号。
该抽象数据类型可具体定义如下:
ADTQUAdraticis
一个二次多项式q,其二次项、一次项和常数项的系数分别用a,b,c表示
//初始化二项式,用于赋给a,b,c值的每个对应参数的默认值设为0
voidInit(Quadratic&
q,floataa=0,floatbb=0,floatcc=0);
//两个二项式相加
QuadraticAdd(Quadratic&
q1,Quadratic&
q2);
//二项式求值
floatEval(Quadratic&
q,floatx);
//求二项式方程的根,两个实根由引用参数r1和r2带回
intRoot(Quadratic&
q,float&
r1,float&
r2);
//输出二项式
voidPrint(Quadratic&
q);
endQUAdratic
这里假定数据部分的二次多项式q是类型名为Quadratic的一个结构对象,该类型的具体定义如下:
structQuadratic{
floata,b,c;
(1)初始化a,b和c的值
q,floataa,floatbb,floatcc)
{
q.a=aa;
q.b=bb;
q.c=cc;
(2)做两个多项式加法,返回它们的和
q2)
Quadraticq;
q.a=q1.a+q2.a;
q.b=q1.b+q2.b;
q.c=q1.c+q2.c;
returnq;
(3)根据给定x的值计算多项式的值并返回
floatEval(Quadratic&
q,floatx)
return(q.a*x*x+q.b*x+q.c);
(4)求二项式方程的根,两个实根由引用参数r1和r2带回
r2)
if(q.a==0)return-1;
//不是二次方程返回-1
floatx=q.b*q.b-4*q.a*q.c;
if(x>
=0){
r1=float(-q.b+sqrt(x))/(2*q.a);
//sqrt(x)为计算x的平方根,该函数存在于系统头文件math.h中
r2=float(-q.b-sqrt(x))/(2*q.a);
return1;
//有实根返回1
elsereturn0;
//无实根返回0
(5)输出二项式
q)
if(q.a)cout<
<
q.a<
"
x**2"
;
if(q.b){
if(q.b>
0)cout<
+"
q.b<
x"
elsecout<
if(q.c){
if(q.c>
q.c;
cout<
endl;
假定使用如下调试程序:
#include<
iostream.h>
math.h>
structQuadratic{
};
//初始化二项式
//两个二项式相加
//二项式求值
//求二项式方程的根,两个实根又引用参数r1和r2带回
//输出二项式
//各函数定义已经在上面给出,这里从略
voidmain()
{
Quadratica,b,c;
Init(a,2,5);
Print(a);
Eval(a,4)<
floatx1,x2;
intn=Root(a,x1,x2);
if(n==1)cout<
x1<
'
'
x2<
Init(b,3,-8,4);
Print(b);
n=Root(b,x1,x2);
c=Add(a,b);
Print(c);
程序运行结果如下:
2x**2+5x
52
0-2.5
3x**2-8x+4
20.666667
5x**2-3x+4