1、2019/8/26,1,数据结构及其应用,(用面向对象方法与C描述),2019/8/26,2,第一章 概述,研究对象:信息的表示方法、数据的组织方法、操作算法设计 意义地位:数据结构算法程序 程序设计的基础系统软件的核心 发展过程:数值计算 非数值计算建立数学模型 客体及其关系的表示设计数值计算方法 数据的组织操作算法的设计非数值计算应用的发展,促进了数据结构的研究和发展以及其体系的完善。,2019/8/26,3,基本术语,数 据:描述客观事物的且能由计算机处理的数值、字符等符号 数据元素:数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理(记录、结点、表目、元素) 数 据 项:数据
2、元素的某一属性。数据元素可以由若干数据项组成,数据项可以由若干更小的款项(组合项、原子项)组成。数据项又称域、字段 关 键 码:能起唯一标识(数据元素)作用的数据项 数据结构:一组同类的数据元素、其间的关系及其上的一组操作所构成的整体,称为一个数据结构,2019/8/26,4,数据结构的描述方式,逻辑结构:是对数据元素之间逻辑关系(抛开具体的关系含义以及存储方式等)的描述,它可以用一个数据元素的集合和定义在此集合上的几个关系来表示。通常可用图形表示,圆圈表示数据元素,箭头表示关系:物理结构:数据结构在计算机中的具体表示和实现,又称存储结构,E i,E i+1,数据元素,数据元素,关系,2019
3、/8/26,5,数据结构的分类,按逻辑结构分类:纯集合型结构:数据元素之间除了“同属于一个集合”这一关系外,别无其他关系线性结构:数据元素之间存在“一个跟着一个”的序列关系树型结构:数据元素之间存在“每个元素只能跟着一个元素但可以有多个元素跟着它”的层次关系图状结构:任意两个数据元素之间都可能存在关系 按存储结构分类:顺序存储结构链式存储结构索引存贮结构,2019/8/26,6,基本操作:任一数据结构均有一组相应的基本操作, 有时操作不同,用途迥异(如栈和队列),常用的基本操作有插入、 删除、查找、更新、排序等 算 法:算法是为了解决给定的问题而规定的一个有限长的操作步骤序列,则重于解决问题的
4、方法和步骤。当算法由计算机语言表示时称为程序(代码) 算法设计目标:可维护性可靠性(正确性、健壮行)可读性高效率(时间、空间),2019/8/26,7,第二章 线性表,2。1 线性表的逻辑结构定义:由相同种类的数据元素组成的一个有穷序列称为一个线性表。“一个跟着一个”符号表示法:L(e1,e2,en)图形表示法:,e2,en,e1,2019/8/26,8,其中: ei -表示线性表 L 的第 i 个数据元素n -表示线性表 L 的表长(n=0)n=0 时的线性表称为空表ei-1 称为 ei 的前驱,ei+1 称为 ei 的后继线性表的基本操作:(1)初始化(置空表)可由构造函数实现(2)求表长
5、( Length )(3)查找或定位( Find )(4)插入( Insert ) (5)删除( Remove )(6)排序( Sort )(7)判空( IsEmpty),2019/8/26,9,2.2 线性表的顺序存储结构,要实现在计算机内表示一个数据结构,要解决两种信息的存贮问题:数据元素本身的存贮数据元素之间关系的存贮 定义:利用内存物理结构上的邻接特点,实现线性表的“一个跟着一个”这一序列关系的存贮方式,称为线性表的顺序存贮结构,其上的线性表称为顺序表。 顺序表的类定义:利用数组作为顺序表的存储结构,它被封装在类的私有域中,2019/8/26,10,template class Seq
6、List Public:SeqList(int MaxSize=defaultSize);SeqList( ) delete data;int Length( ) const return last+1;int Find(Type / last 为表中最后元素的下标,last=-1 时表示空表,2019/8/26,11,上述顺序表定义中的数据成员 Maxsize 是为判断顺序 表是否为满而设,last 是为便于判断顺序表是否为空、求 表长、置空表而设:last=Maxsize 1表示顺序表已满,此时再进行插入操作会导致上溢错误;last=-1 表示顺序表为空表,此时再进行删除操作会导致下溢错误
7、;last+1 代表顺序表的表长;将 last 赋值为 1 可实现置空表操作。 由上可知:合理地设置数据成员可大大简化算法的设计及提高算法的效率。顺序表不仅仅包含存放其数据元素的数组,它还应包括一些有用的数据成员,以及相应的操作,它们是一个整体:,2019/8/26,12,顺序表之整体概念:,data,0,1,last,Maxsize,last,数组下标,数组,变量,操作算法,Maxsize-1,初始化操作,插入操作,删除操作,查找操作,排序操作,. . . . . .,. . .,. . .,. . .,2019/8/26,13,顺序表的基本操作(算法),(1)顺序表初始化操作算法 temp
8、late Seqlist:Seqlist(int sz) /构造函数,通过指定参数 sz 定义数组的长度,并将 last 置为 1 /即置空表 if(sz0)Maxsize=sz;last=-1; / last+1=0 , 表明表中无元素,空表data=new TypeMaxsize; ,2019/8/26,14,(2)顺序表查找操作,template int Seqlist:Find(Type ,2019/8/26,15,(3)顺序表插入操作,为了把新元素 x 插入到 i 处,必须把从 i 到 last 的所有元素成块向后移动一个元素位置,以空出第 i 个位置供 x 插入:,x,2,3,1,
9、先移动后面元素,0,i-1,i,i+1,last,. . .,. . .,. . .,. . .,. . .,. . .,2019/8/26,16,template int Seqlist:Insert(Type ,2019/8/26,17,(4)顺序表删除操作,为了删除第 i 个元素,必须把从 i1 到 last 的所有元素向前移动一个元素位置,把第 i 个元素覆盖掉:,1,2,. . .,0,i-1,i,i+1,last-1,last,1,. . .,. . .,. . .,. . .,. . .,2019/8/26,18,template int Seqlist:Remove(Type
10、,2019/8/26,19,顺序存储结构的优缺点,优点:(1)算法简单、可读性好、开发代价低 缺点:(1)插入、删除操作时需要移动大量元素,效率较低;(2)最大表长难以估计,太大了浪费空间,太小了容易溢出。,2019/8/26,20,顺序表应用举例,当将两个顺序表作集合考虑时的“并”与“交”操作算法 template void Union(Seqlist ,2019/8/26,21,template void Intersection( Seqlist ,2019/8/26,22,多项式及其运算,A(x)=a0x + a1x +a2x +an-1x + anx = B(x)=b0x + b1x
11、 +b2x +bn-1x +bnx = A(x)+B(x)=实际应用中,上述一元多项式中的很多系数有可能为零, 即为稀疏多项式,如下式所示:, aix,i=0,n,i,0,1,2,n-1,n,0,1,2,n-1,n, bix,i,i=0, (ai+bi)x,n,i=0,i,P (x)=1.2+51.3x +3.7x,50,50,101,P(x)=ci x,i=0,n,ei,c0=1.2 e0=0,c1=51.3 e1=50,c2=3.7 e2=101,2019/8/26,23,多项式的表示,对于稀疏多项式,采用二元组表示法可以大大节省存储 空间:(1)将稀疏多项式的每一项用二元组表示客体的表示
12、方法(2)用一顺序表(一维数组)来存放上述的二元组数据的组织方法,c0,c1,ci,cn,e0,e1,ei,en,系数,指数,. . .,. . .,. . .,. .,. . .,2019/8/26,24,多项式二元组的类定义客体的表示方法,class Polynomial; / 多项式类的前视声明 class term / 多项式中项(二元组)的类定义 friend Polynomial; / 定义 Polynomial 类为 term 类的友元类private :float coef; / 系数int exp; / 指数 ,2019/8/26,25,多项式的类定义数据的表示方法,clas
13、s Polynomial public :. . . / 成员函数声明(构造、释构、相加等函数)private :int MaxTerms ; /共享空间(顺序表)的最大项数static term termArrayMaxTerms;/存放二元组的数组,存放多个多项式的共享空间static int free ; / 共享空间中自由空间之起始下标int start , finish ; / 多项式在共享空间中的首、尾下标 ,2019/8/26,26,多项式的相加,A(x)=aix B(x)=bjxC(x)=A(x)+B(x),n,m,i=0,j=0,e i,e j,A . Start A . f
14、inish,B . Start B . finish,free MaxTerm-1,2019/8/26,27,多项式AB算法思路:,(1)保留A、B两个多项式,将AB放人C中;(2)开始时 C.start = free;(3)设置两个指针 a 和 b 分别作为 A 与 B 的检测指针,开始时分别指向 A 与 B 的首项,即:a = A . start ; b = B . start;(4)当两个指针都未超出相应多项式的最末位置时,比较它们所指示的对应项的指数:若指数相等,则对应项系数相加,若相加结果不为零,则在 C 中加入一个新项若指数不等,则把指数小者拷贝到 C 中(5)当两个指针中有一个超
15、出了相应多项式的最末位置,则将另 一个多项式的剩余部分拷贝到 C 中,2019/8/26,28,Polynomial Polynomial : Add ( Polynomial B ) Polynomial C; int a = start; int b =B.start; C.start = free; float c;while ( a : NewTerm( termArrayb.coef , termArrayb.exp);b+ ; break ;case : NewTerm( termArraya.coef , termArraya.exp);a+ ; for ( ; a = fini
16、sh ; a+ ) NewTerm( termArraya.coef , termArraya.exp);for ( ; b = B.finish ; b+ ) NewTerm( termArrayb.coef , termArrayb.exp);C.finish=free-1;return C ; ,2019/8/26,29,void Polynomial : NewTerm( float c , int e ) / 把一个新的项(二元组 )追加到多项式 C(x) 中 if ( free = MaxTerms )cout “Too many terms in polynomials” end
17、l ;return ;termArray free . coef = c ;termArray free . exp = e ;free + ; ,2019/8/26,30,作业:,定义多项式类的求表长、查找、插入、删除、判空 表判满表、读取(第 i 个元素)等成员函数,并用这些 函数实现前述的两个多项式的相加操作。提示: (1)定义查找指数相等的元素的成员函数 (2)仿照前述的顺序表合并操作算法,先从多项式 B 中 读取一元素,在 A 中查找有无指数相等元素: 若无,则有序插入 A 中; 若有,则系数相加:若和为零,则从 A 中删除相应元素;否则用新系数构造新元素,并插入 A 中相应位置,2
18、019/8/26,31,稀疏矩阵(Sparse Matrix)数值计算中的顺序表设计,0 0 0 22 0 0 15 0 11 0 0 0 17 0 A = 0 0 0 -6 0 0 00 0 0 0 0 39 091 0 0 0 0 0 00 0 28 0 0 0 0矩阵 A 是一个 6 行 7 列的稀疏矩阵,只有 8 个非零元素,其他均为零。因此用二维数组来存储稀疏矩阵的空间利用率较低,必须考虑对稀疏矩阵的压缩存储表示。,2019/8/26,32,稀疏矩阵的三元组表示法:(1)将稀疏矩阵的非零元素用三元组表示( 表示稀疏矩阵的第 row 行、第 column 列的值为 value)客体的表
19、示方法(2)用一顺序表(一维数组)来存放上述三元组(每一个三元组即为顺序表的一个数据元素)并按行优先顺序存放数据的组织方法 template class Trituple private :int row, col; Type value; ,2019/8/26,33,矩阵A的三元组表示:,表下标 行(row) 列(col) 值(value)0 0 3 221 0 6 152 1 1 113 1 5 174 2 3 -65 3 5 396 4 0 917 5 2 28,2019/8/26,34,稀疏矩阵的类声明:,template class SparseMatrix public:Spars
20、eMatrix(int MaxTerms=defaultSize);SparseMatrix() delete smArray; SparseMatrix Compression(smData);SparseMatrix Transpose();SparseMatrix Add(SparseMatrix b);SparseMatrix Multiply(SparseMatrix b);private:int Rows, Cols, Terms,MaxTerms;Trituple smArrayMaxTerms; ,2019/8/26,35,说明:(1)压缩前的稀疏矩阵为 Rows 行, Col
21、s 列的矩阵smData ,压缩后的稀疏矩阵存放在一维数组smArray 中,其中的元素为 Trituple 类型的对象。声明中的 Terms 对应于顺序表定义中的 last,MaxTerms 对应于顺序表定义中的 Maxsize,smArray 对应于顺序表定义中的 data(2)为稀疏矩阵声明了四种操作:压缩(Compression)转置(Transpose)相加(Add)相乘(Multiply)根据实际需要还可以声明其他操作。(3)数值计算与非数值计算的数据结构中所定义的基本操作有很大的不同,2019/8/26,36,稀疏矩阵的转置操作,快速转置算法思路:(1)引入两个辅助数组 rowS
22、ize 和 rowStart rowSize i 表示稀疏矩阵第 i 列的非零元素个数rowStart i 表示稀疏矩阵第 i 列的第一个(行号最小)非零元素在转置矩阵的三元组表中的位置。 显然应有:rowStart i + rowSize i = rowStart i+1 ,. . .,. . .,. . .,共有 rowSize i 个元素,2019/8/26,37,上述公式表示,若已知稀疏矩阵第 i 列的第一个非零元素在转置 矩阵的三元组表中的位置 rowStart i , 以及稀疏矩阵第 i 列的非零 元素个数 rowSize i , 就可以算出第 i+1 列非零元素在转置矩阵的 三元
23、组表中的位置 rowStart i+1 另外,根据转置矩阵的定义可知:rowStart 0 = 0 因此:rowStart 1 = rowSize 0 + rowStart 0 = rowSize 0 rowStart 2 = rowSize 1 + rowStart 1 . . . . . .因此,只要预先统计得到 rowSize i ( i = 0 , 1 , 2 , . . .) 就可以得到第 i + 1 列非零元素在转置矩阵的三元组表中的位置,2019/8/26,38,template SparseMatrix SparseMatrix: FastTranspos( )/ int *r
24、owSize = new intCols; int *rowStart = new intCols;SparseMatrix b; b.Rows = Cols; b.Cols = Rows; b.Terms = Terms;if (Terms 0 ) for (int i = 0; iCols; i +) rowSizei = 0;for (i=0;iTerms;i+) rowSizesmArrayi.col+;rowStart0=0;for (i=1;iCols;i+) rowStarti=rowStarti-1+rowSizei-1;for (i=0;iTerms;i+)int j=row
25、StartsmArrayi.col;b.smArrayj.row=smArrayi.col;b.smArrayj.col=smArrayi.row;b.smArrayj.value=smArrayi.value;rowStartsmArrayi.col+;delete rowSize; delete rowStart; return b; ,2019/8/26,39,2。5 字符串,定义: 字符串(简称为串) 是 n ( n = 0 ) 个字符的有限序列通常可记为:S = a0 a1 a2 an-1 其中: 串名S串值引号中的内容n串长,即串中的字符个数(不包括串结束符 0 )空串 n = 0
26、 的串(但包含串结束符)空白串仅由若干个空格字符组成的串,其长度不为零子串从非空串中连续取出的若干个字符组成的串子串的位置子串的第0个字符在原串中的位置可以认为:串是限制数据元素为字符的顺序表,2019/8/26,40,2.5.1 字符串抽象数据类型和类定义,class String public:String(const String ,2019/8/26,41,有了上述的串类定义,就可以进行下列操作:,String s1; String s2 ( “ Hello World ” ); s1 = s2; String s3 ( “ ; nice to here ! ” ); s1 + = s
27、3; int len=s1.length(); String s4; s4=s1(6,5); If (s1=s2) If (s1!=s2) If (! s1) Char c=s16; s16=w;,2019/8/26,42,文本编辑,计算机应用中要涉及大量的文本文件,文本文件由大量的串 (行)组成,在某些文本文件(如源程序)中,串(行)长差异很大,若每行都用等长的串来存贮,则会浪费存贮空间解决的办法之一是建立一个很大的字符数组作为所有串的共享空间串值共享空间,再为每个串建立一个描述子,用于描述该串的长度以及该串在串值共享空间中的位置等信息,并将这些描述子存入一顺序表中,参见下图:,2019/8
28、/26,43,行表(linelist) 串值共享空间(space) MaxSize-1,.,.,.,.,free,行号,0 1 2 3,行长 位置,行2,行3,行0,行1,. . .,. . . .,. . . .,自由空间起始地址,0,串值共享空间String(串) 行表Seqlist(顺序表)设计行内字符插入、删除操作算法 设计整行插入、删除操作算法,2019/8/26,44,第三章 链表,顺序表有下列缺点: (1)插入、删除操作时需要移动大量元素,效率较低;(2)最大表长难以估计,太大了浪费空间,太小了容易溢出。因此,在插入和删除操作是经常性操作的应用场合 选用顺序存储结构不太合适,此时
29、可以选用链式存储结 构。定义:用指针来表示数据元素之间关系的存储结构称之为链式存储结构。,2019/8/26,45,定义:用由指针连接起来的一串结点来存储一个线性表的存储结构称为线性链式存储结构,简称链表。当每一结点中只有一个指针,并用来表示一个数据元素到其后继元素之间的接续关系,则称这种存储结构为单链表。 注:此处的结点是指通过指针型变量动态索取到的存储空间,. . .,first,first头指针 指针域 (link) last last 尾指针 数据元素域 (data) 空指针,结点1,头结点,结点0,结点n-1,2019/8/26,46,上述的单链表表头设置了一头结点,头结点的数据 域
30、中可以为空,或者存放一些辅助数据。设置头结点的目的是为了简化对空表的特殊处理, 使得算法更简单、更有效。对于带头结点的单链表,可以很容易地表示空链表:头指针 头结点,first,last,尾指针,2019/8/26,47,用模板定义的单链表类,template class List; template class ListNode friend class List ; public:ListNode( );ListNode(const Type ,2019/8/26,48,template class List public:List( ) last=first=new ListNode (
31、value,NULL);List( );void MakeEmpty( );int Length( ) const;ListNode *Find(Type value);ListNode *Find(int i);int Insert(Type value,int i);Type *Remove(int i);Type *Get(int i);private:ListNode *first, *last; ,2019/8/26,49,ListNode类(链表结点类)的成员函数的实现,template void ListNode:ListNode( ):link(NULL) template v
32、oid ListNode:ListNode(const Type ,2019/8/26,50,Void InsertAfter(ListNodeType) *p):功能:将 p 所指的结点(*p)链接成为当前结点(*this)的后继结点,this,data,link,data,link,data,link,p,p-link=link,Link=p,(1),(2),当前结点,2019/8/26,51,RemoveAfter( ),data,link,data,link,data,link,当前结点 要删除的结点功能:删除当前结点 ( *this ) 的后继结点,并返回该结点的指针。,(1)tem
33、pptr,(2) link=tempptr-link,this,tempptr-link,2019/8/26,52,List类(链表类)的成员函数的实现,template void List:MakeEmpty( ) / 将当前链表置为空表ListNode *q ;while (first -link != NULL)/ 循环删除头结点的后继结点,直到无后继结点为止q=first -link ; first -link=q -link ; delete q ;last=first;/ 最后让 last 指向头结点,完成置空表操作 ,first,(1) q=first-link,(2) firs
34、t-link=q-link,(最后)last,头结点,2019/8/26,53,template int List:Insert(Type value,int i); / 将值为 value 的新数据元素插入到链表中结点 i 之前ListNode *p = Find(i-1);/ 查找结点 i-1if (p=NULL) return 0;/ 结点 i-1 不存在,插入失败ListNode *newnode=GetNode(value,p-link);/ 创建新结点/ 并使新结点指向结点 i (1)if (p-link=NULL) last=newnode;/ 若结点 i 不存在,则新结点将/
35、是表尾结点p-link=newnode;/ 让结点 i-1 指向新结点,实现插入 (2)return 1; ,结点 i-1,结点 i,新结点,p,newnode,(1),(2),2019/8/26,54,template Type *List : Remove( int i ) / 删除结点 i ,若成功,则返回该结点的数据元素(地址),/ 否则返回NULLListNode *p= Find(i-1) , *q ; / 查找结点 i-1if ( p=NULL | p-link=NULL) return NULL;/ 若结点 i-1 或者/ 结点 i 不存在,则返回 NULL , 删除失败q=p
36、-link; / (1)p-link=q-link;/ (2)Type value=q-data;if (q=last) last=p;delete q;return ,结点 i-1 结点 i 结点 i+1,p q,(1),(2),2019/8/26,55,template ListNode *List:Find( int i ) / 查找结点 i , 若找到,则返回该结点的指针,否则返回NULLif ( i *p=first-link;/ p 指向结点0int j=0;while(p!= NULL ,2019/8/26,56,3.1.6 单链表的游标(Iterator)类,2019/8/26
37、,57,单链表游标类声明,Template class ListIterator public:ListIterator(const List ,2019/8/26,58,单链表游标类成员函数的定义,template Boolean ListIterator:NotNull( ) / 检查游标结点(当前指针 current 所指的结点)是否为不空(注: /此处结点不空是指该结点的指针不空)。若不空,则返回真, / 否则返回假if ( current != NULL ) return True;else return False; template Boolean ListIterator:Ne
38、xtNotNull( ) / 检查游标结点(游标所指的结点)的后继结点是否为不空。 / 若不空,则返回真;否则返回假if ( current != NULL ,2019/8/26,59,template ListNode * ListIterator:First( ) / 使游标指向头结点if ( list.first-link != NULL )current = list.first; / 若头结点的指针/域不空,即链表为非空表,则使游标指向头结点else current = NULL; / 否则置空游标 return current; template ListNode * ListIt
39、erator:Next( ) / 使游标指向后继结点if ( current != NULL ,2019/8/26,60,2019/8/26,61,2019/8/26,62,2019/8/26,63,2019/8/26,64,2019/8/26,65,2019/8/26,66,2019/8/26,67,2019/8/26,68,2019/8/26,69,2019/8/26,70,2019/8/26,71,2019/8/26,72,2019/8/26,73,2019/8/26,74,2019/8/26,75,2019/8/26,76,2019/8/26,77,2019/8/26,78,2019/
40、8/26,79,2019/8/26,80,2019/8/26,81,2019/8/26,82,2019/8/26,83,2019/8/26,84,2019/8/26,85,2019/8/26,86,2019/8/26,87,2019/8/26,88,2019/8/26,89,2019/8/26,90,2019/8/26,91,2019/8/26,92,2019/8/26,93,2019/8/26,94,2019/8/26,95,2019/8/26,96,2019/8/26,97,2019/8/26,98,2019/8/26,99,2019/8/26,100,2019/8/26,101,2019/8/26,102,2019/8/26,103,2019/8/26,104,2019/8/26,105,2019/8/26,106,2019/8/26,107,2019/8/26,108,2019/8/26,109,2019/8/26,110,2019/8/26,111,2019/8/26,112,2019/8/26,113,