收藏 分享(赏)

算法与数据结构第5章 数组和广义表.ppt

上传人:dreamzhangning 文档编号:3312452 上传时间:2018-10-11 格式:PPT 页数:66 大小:344KB
下载 相关 举报
算法与数据结构第5章  数组和广义表.ppt_第1页
第1页 / 共66页
算法与数据结构第5章  数组和广义表.ppt_第2页
第2页 / 共66页
算法与数据结构第5章  数组和广义表.ppt_第3页
第3页 / 共66页
算法与数据结构第5章  数组和广义表.ppt_第4页
第4页 / 共66页
算法与数据结构第5章  数组和广义表.ppt_第5页
第5页 / 共66页
点击查看更多>>
资源描述

1、第5章 数组和广义表,5.1 数组,5.2 稀疏矩阵,本章小结,5.3 广义表,5.1.1 数组的基本概念数组是n(n1)个相同类型数据元素a1,a2,an构成的有限序列,且该有限序列存储在一块地址连续的内存单元中。由此可见,数组的定义类似于采用顺序存储结构的线性表。,数组具有以下性质:(1) 数组中的数据元素数目固定。一旦定义了一个数组,其数据元素数目不再有增减变化。(2) 数组中的数据元素具有相同的数据类型。(3) 数组中的每个数据元素都和一组惟一的下标值对应。(4) 数组是一种随机存储结构。可随机存取数组中的任意数据元素。,5.1.2 数组的存储结构在一维数组中,一旦a1的存储地址LOC

2、(a1)确定,并假设每个数据元素占用k个存储单元,则任一数据元素ai的存储地址LOC(ai)就可由以下公式求出:LOC(ai)=LOC(a1)+(i-1)*k (0in)上式说明,一维数组中任一数据元素的存储地址可直接计算得到,即一维数组中任一数据元素可直接存取,因此,一维数组是一种随机存储结构。同样,二维及多维数组也满足随机存储特性。,对于一个m行n列的二维数组Amn,有:,将Am*n简记为A,A是这样的一维数组:A=(a1,a2,ai,am) 其中,ai=(ai,1,ai,2,ai,n) (1im)。,二维数组同样满足数组的定义。一个二维数组可以看作是每个数据元素都是相同类型的一维数组的一

3、维数组。以此类推,任何多维数组都可以看作一个线性表,这时线性表中的每个数据元素也是一个线性表。多维数组是线性表的推广。,对于二维数组来说,由于计算机的存储结构是线性的,如何用线性的存储结构存放二维数组元素就有一个行列次序排放问题。以行序为主序的存储方式:即先存储第1行,然后紧接着存储第2行,最后存储第m行。此时,二维数组的线性排列次序为:a1,1,a1,2,a1,n,a2,1,a2,2,a2,n,am,1,am,2,am,n,对一个已知以行序为主序的计算机系统中,当二维数组第一个数据元素a1,1的存储地址LOC(a1,1)和每个数据元素所占用的存储单元k确定后,则该二维数组中任一数据元素ai,

4、j的存储地址可由下式确定:LOC(ai,j)=LOC(a1,1)+(i-1)*n+(j-1)*k其中n为列数。,同理可推出在以列序为主序的计算机系统中有:LOC(ai,j)=LOC(a1,1)+(j-1)*m+(i-1)*k 其中m为行数。,例 按行优先顺序和按列优先顺序列出四维数组A2222所有元素在内存中的存储次序。,解: 按行优先的存储次序:A0000, A0001, A0010, A0011, A0100, A0101,A0110, A0111, A1000,A1001, A1010, A1011,A1100, A1101, A1110,A1111,按列优先的存储次序:A0000, A

5、1000, A0100,A1100, A0010, A1010,A0110, A1110, A0001,A1001, A0101, A1101,A0011, A1011, A0111,A1111,例 对二维数组float a54计算:(1) 数组a中的数组元素数目;(2) 若数组a的起始地址为2000,且每个数组元素长度为32位(即4个字节),数组元素a32的内存地址。,解:由于C语言中数组的行、列下界均为0,该数组行上界为5-1=4,列上界为4-l=3,所以该数组的元素数目共有(4-0+1)*(3-0+1)=5*4=20个。又由于C语言采用行序为主序的存储方式,则有:LOC(a3,2)=LO

6、C(a0,0)+(i*n+j)*k=2000+(3*4+2)*4=2056,5.1.3 特殊矩阵的压缩存储特殊矩阵的主要形式有:(1)对称矩阵(2)上三角矩阵下三角矩阵(3)对角矩阵 它们都是方阵,即行数和列数相同。,1. 对称矩阵的压缩存储若一个n阶方阵Ann中的元素满足ai,j=aj,i(0i,jn-1),则称其为n阶对称矩阵。由于对称矩阵中的元素关于主对角线对称,因此在存储时可只存储对称矩阵中上三角或下三角中的元素,使得对称的元素共享一个存储空间。这样,就可以将n2个元素压缩存储到个元素的空间中。不失一般性,我们以行序为主序存储其下三角(包括对角线)的元素。,n2个元素 n(n+1)/2

7、个元素A0n-1,0n-1 B0n(n+1)/2-1 aij bk,k=,+ j ij,+ i ij,上三角矩阵:,k=,+ j i ij时,ij时,下三角矩阵:,k=,ij时,ij时,2. 对角矩阵的压缩存储若一个n阶方阵A满足其所有非零元素都集中在以主对角线为中心的带状区域中,则称其为n阶对角矩阵。其主对角线上下方各有b条次对角线,称b为矩阵半带宽,(2b+1)为矩阵的带宽。对于半带宽为b(0b(n-1)/2)的对角矩阵,其|i-j|b的元素ai,j不为零,其余元素为零。下图所示是半带宽为b的对角矩阵示意图。,半带宽为b的对角矩阵,当b1时称为三对角矩阵。 其压缩地址计算公式如下:k=2i

8、+j,A B aij bk,思考题:为什么采用压缩存储,需要解决什么问题?,5.2 稀疏矩阵一个阶数较大的矩阵中的非零元素个数s相对于矩阵元素的总个数t十分小时,即st时,称该矩阵为稀疏矩阵。例如一个100100的矩阵,若其中只有100个非零元素,就可称其为稀疏矩阵。,5.2.1 稀疏矩阵的三元组表示稀疏矩阵的压缩存储方法是只存储非零元素。由于稀疏矩阵中非零元素的分布没有任何规律,所以在存储非零元素时还必须同时存储该非零元素所对应的行下标和列下标。稀疏矩阵中的每一个非零元素需由一个三元组:(i, j, ai,j) 唯一确定,稀疏矩阵中的所有非零元素构成三元组线性表。,假设有一个67阶稀疏矩阵A

9、(为图示方便,所取的行列数都很小),A中元素如下图所示。则对应的三元组线性表为:(0,2,1),(1,1,2),(2,0,3),(3,3,5), (4,4,6),(5,5,7),(5,6,4),一个稀疏矩阵A,若把稀疏矩阵的三元组线性表按顺序存储结构存储,则称为稀疏矩阵的三元组顺序表。则三元组顺序表的数据结构可定义如下:,#define MaxSize 100 /矩阵中非零元素最多个数typedef struct int r; /行号int c; /列号ElemType d; /元素值 TupNode; /三元组定义typedef struct int rows; /行数值int cols;

10、/列数值int nums; /非零元素个数TupNode dataMaxSize; TSMatrix; /三元组顺序表定义,其中,data域中表示的非零元素通常以行序为主序顺序排列,它是一种下标按行有序的存储结构。这种有序存储结构可简化大多数矩阵运算算法。下面的讨论假设data域按行有序存储。,(1) 从一个二维矩阵创建其三元组表示以行序方式扫描二维矩阵A,将其非零的元素插入到三元组t的后面。,void CreatMat(TSMatrix ,(2) 三元组元素赋值先在三元组t中找到适当的位置k,将kt.nums个元素后移一位,将指定元素x插入到t.datak处。,8,修改元素,8,增加元素,算

11、法如下:int Value(TSMatrix /查找列,上述蓝色部分教材中有误。,if (t.datak.r=rs ,(3) 将指定位置的元素值赋给变量先在三元组t中找到指定的位置,将该处的元素值赋给x。算法如下:int Assign(TSMatrix t,ElemType ,(4) 输出三元组从头到尾扫描三元组t,依次输出元素值。算法如下:void DispMat(TSMatrix t) int i;if (t.nums=0) return;printf(“t%dt%dt%dn“,t.rows,t.cols,t.nums);printf(“ -n“);for (i=0;it.nums;i+)

12、printf(“t%dt%dt%dn“,t.datai.r,t.datai.c, t.datai.d); ,(5) 矩阵转置对于一个mn的矩阵Amn,其转置矩阵是一个nm的矩阵。设为Bnm,满足ai,j=bj,i,其中1im,1jn。,void TranTat(TSMatrix t,TSMatrix p+) /p为t.data的下标,if (t.datap.c=v) tb.dataq.r=t.datap.c;tb.dataq.c=t.datap.r;tb.dataq.d=t.datap.d;q+; ,以上算法的时间复杂度为O(t.cols*t.nums),而将二维数组存储在一个m行n列矩阵中时

13、,其转置算法的时间复杂度为O(m*n)。最坏情况是当稀疏矩阵中的非零元素个数t.nums和m*n同数量级时,上述转置算法的时间复杂度就为O(m*n2)。对其他几种矩阵运算也是如此。可见,常规的非稀疏矩阵应采用二维数组存储,只有当矩阵中非零元素个数s满足sm*n时,方可采用三元组顺序表存储结构。这个结论也同样适用于下面要讨论的十字链表。,5.2.2 稀疏矩阵的十字链表表示十字链表为稀疏矩阵的每一行设置一个单独链表,同时也为每一列设置一个单独链表。这样稀疏矩阵的每一个非零元素就同时包含在两个链表中,即每一个非零元素同时包含在所在行的行链表中和所在列的列链表中。这就大大降低了链表的长度,方便了算法中

14、行方向和列方向的搜索,因而大大降低了算法的时间复杂度。,(a) 结点结构 (b) 头结点结构,对于一个mn的稀疏矩阵,每个非零元素用一个结点表示,结点结构可以设计成如下图(a)所示结构。其中i,j,value分别代表非零元素所在的行号、列号和相应的元素值;down和right分别称为向下指针和向右指针,分别用来链接同列中和同行中的下一个非零元素结点。,十字链表中设置行头结点、列头结点和链表头结点。它们采用和非零元素结点类似的结点结构,具体如上图(b)所示。其中行头结点和列头结点的i,j域值均为0;行头结点的right指针指向该行链表的第一个结点,它的down指针为空;列头结点的down指针指向

15、该列链表的第一个结点,它的right指针为空。行头结点和列头结点必须顺序链接,这样当需要逐行(列)搜索时,才能一行(列)搜索完后顺序搜索下一行(列),行头结点和列头结点均用link指针完成顺序链接。,一个稀疏矩阵,十字链表结点结构和头结点的数据结构可定义如下: #define M 3 /矩阵行 #define N 4 /矩阵列 #define Max (M)(N)?(M):(N) /矩阵行列较大者 typedef struct mtxn int row; /行号int col; /列号struct mtxn *right,*down; /向右和向下的指针union int value;stru

16、ct mtxn *link; tag; MatNode; /十字链表类型定义,思考题:稀疏矩阵的十字链表表示给我们什么启示?例如,要存放若干班的学生信息,每个班的人数不定,如何设计其存储结构?,5.3 广义表 1. 广义表的定义广义表简称表,它是线性表的推广。一个广义表是n(n0)个元素的一个序列,若n=0时则称为空表。设ai为广义表的第i个元素,则广义表GL的一般表示与线性表相同:GL=(a1,a2,ai,an)其中n表示广义表的长度,即广义表中所含元素的个数,n0。如果ai是单个数据元素,则ai是广义表GL的原子;如果ai是一个广义表,则ai是广义表GL的子表。,广义表具有如下重要的特性:

17、(1)广义表中的数据元素有相对次序;(2)广义表的长度定义为最外层包含元素个数;(3)广义表的深度定义为所含括弧的重数。其中,原子的深度为0,空表的深度为1;(4)广义表可以共享;一个广义表可以为其他广义表共享;这种共享广义表称为再入表;(5)广义表可以是一个递归的表。一个广义表可以是自已的子表。这种广义表称为递归表。递归表的深度是无穷值,长度是有限值;(6)任何一个非空广义表GL均可分解为表头head(GL) = a1和表尾tail(GL) = ( a2,an) 两部分。,为了简单起见,下面讨论的广义表不包括前面定义的再入表和递归表,即只讨论一般的广义表。另外,我们规定用小写字母表示原子,用

18、大写字母表示广义表的表名。例如:A=()B=(e)C=(a,(b,c,d)D=(A,B,C)=(),(e),(a,(b,c,d)E=(a,(a,b),(a,b),c),如果把每个表的名字(若有的话)写在其表的前面,则上面的5个广义表可相应地表示如下:A()B(e)C(a,(b,c,d)D(A(),B(e),C(a,(b,c,d)E(a,(a,b),(a,b),c)若用圆圈和方框分别表示表和单元素,并用线段把表和它的元素(元素结点应在其表结点的下方)连接起来,则可得到一个广义表的图形表示。例如,上面五个广义表的图形表示如下图所示。,A() B(e) C(a,(b,c,d) D(A(),B(e),

19、C(a,(b,c,d) E(a,(a,b),(a,b),c),2. 广义表的存储结构广义表是一种递归的数据结构,因此很难为每个广义表分配固定大小的存储空间,所以其存储结构只好采用动态链式结构。,广义表的存储结构,typedef struct lnode int tag; /结点类型标识union ElemType data;struct lnode *sublist; val;struct lnode *link; /指向下一个元素 GLNode; /广义表结点类型定义,广义表的两种基本情况 :,为原子的情况 :,3. 广义表的运算 (1) 求广义表的长度在广义表中,同一层次的每个结点是通过l

20、ink域链接起来的,所以可把它看做是由link域链接起来的单链表。这样,求广义表的长度就是求单链表的长度,可以采用以前介绍过的求单链表长度的方法求其长度。,求广义表长度的非递归算法如下:int GLLength(GLNode *g) /g为一个广义表头结点的指针 int n=0;g=g-val.sublist; /g指向广义表的第一个元素while (g!=NULL) n+;g=g-link;return n;,(2) 求广义表的深度对于带头结点的广义表g,广义表深度的递归定义是它等于所有子表中表的最大深度加1。若g为原子,其深度为0。求广义表深度的递归模型f()如下:,f(g)=,0 若g为

21、原子,1 若g为空表,MAXf(subg)+1 其他情况,subg为g的子表,int GLDepth(GLNode *g) /求带头结点的广义表g的深度 int max=0,dep;if (g-tag=0) return 0; /为原子时返回0g=g-val.sublist; /g指向第一个元素if (g=NULL) return 1; /为空表时返回1while (g!=NULL) /遍历表中的每一个元素 if (g-tag=1) /元素为子表的情况 dep=GLDepth(g); /递归调用求出子表的深度if (depmax) max=dep; /max为同一层所求过的子表中深度的最大值g

22、=g-link; /使g指向下一个元素return(max+1); /返回表的深度 ,(3) 输出广义表以h作为带表头附加结点的广义表的表头指针,打印输出该广义表时,需要对子表进行递归调用。,void DispGL(GLNode *g) /g为一个广义表的头结点指针 if (g!=NULL) /表不为空判断 if (g-tag=1) /为表结点时 printf(“(“); /输出(if (g-val.sublist=NULL) printf(“);/输出空子表else DispGL(g-val.sublist);/递归输出子表else printf(“%c“, g-val.data); /为原

23、子时输出元素值if (g-tag=1)printf(“)“);/表结点时输出)if (g-link!=NULL) printf(“,“);DispGL(g-link);/递归输出后续表的内容 ,思考题:多项式运算:是否可以采用广义表的方法存放多项式,如何实现相关算法?,本章小结 本章基本学习要点如下:(1) 理解数组和一般线性表之间的差异。(2) 重点掌握数组的顺序存储结构和元素地址计算方法。(3) 掌握各种特殊矩阵如对称矩阵、上、下三角矩阵和对角矩阵的压缩存储方法。(4) 掌握稀疏矩阵的各种存储结构以及基本运算实现算法。(5) 掌握广义表的定义和广义表的链式存储结构。(6) 掌握广义表的基本运算,包括创建广义表、输出广义表、求广义表的长度和深度。,练习题5p132习题2、3、4、7和8。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报