页数:73页文件大小:277.9 KB来源: 数据结构与算法ppt课件
本课件讲解数组作为结构型线性表的定义与抽象数据类型,给出多维数组的顺序存储与映象函数,随后重点展开特殊矩阵与稀疏矩阵的压缩存储、三元组转置与十字链表表示,最后介绍广义表的概念与两种链式存储结构。
第五章数组和广义表
有关数组的概述
内容提要:
第一节数组的定义
数组是线性表的推广,它是由下标和值组成的偶对的一个集合
(2)数组的抽象数据类型定义
(2)数组的抽象数据类型定义(续)基本操作:InitArray(&A,n,bound1,…,boundn)//构造数组DestroyArray(&A)//销毁数组Value(A,&e,index1,…,indexn)//返回指定数组的元素Assign(A,e,index1,…,indexn)//给数组元素赋值
(3)数组的讨论
(3)数组的讨论(续)
0a11按行序为主序存放1a12…….n-1a1nna21a11a12……..a1na22a21a22……..a2n……..a2n………………….……….am1am2……..amnam1am2Loc(aij)=Loc(a11)+[(i-1)n+(j-1)]*L……..m*n-1amn按列序为主序存放01m-1ma11a21…….am1a12a22……..am2……….a1na2n……..amna11a12a21a22……..……..a1na2n……..am1am2amn………………….Loc(aij)=Loc(a11)+[(j-1)m+(i-1)]*Lm*n-1
第二节数组的顺序表示和实现
(1)数组元素存储约定
(1)数组元素存储约定(续)n
(2)数组的顺序存储表示 #defineMAX_ARRAY_DIM8 typedefstruct{ ElemType*base;//数组维数int*bounds;//数组映象函数基址,由Initarray分配 } Array;(2)数组的顺序存储表示(续)
(3)算法描述StatusInitArray(Array&A,intdim,…){ if(dim<1‖dim>MAX_ARRAY_DIM)returnERROR; A.dim=dim; A.bounds=(int*)malloc(dim*sizeof(int)); if(!A.bounds)exit(OVERFLOW);//ap为va_list类型,是存放变长参数表信息的数组,等价于一次性执行多个scanf(“%d”,&dim)函数for(i=0; i<dim; ++i); { A.bounds[i]=va_arg(ap,int);elemtotal*=A.bounds[i];va_end(ap);(3)算法描述(续)A.base=(Elemtype*)malloc(elemtotal*sizeof(Elemtype)); if(!A.base)exit(OVERFLOW);if(!A.constants)exit(OVERFLOW); B.constants[dim-1]=1;i>=0; --i)A.constants[i]=A.bounds[i+1]*A.constants[i+1];}(3)算法描述(续)
(3)算法描述(续)
//A是n维数组,e为元素变量,随后是n个下标值。
//A是n维数组,e为元素变量,随后是n个下标值。
(4)以二维数组(矩阵)讨论多维数据的基本运算
一个m*n的矩阵Amn和一个n*m的矩阵Bnm相加得到一个m*n的矩阵Cmn其中cij=aij+bij。
矩阵相乘
第三节矩阵的压缩存储
(1)矩阵的讨论
(2)特殊矩阵
(2)特殊矩阵(续)
对称矩阵的压缩存储j(j1)/2i1,ija11a12a21….……..a1n……..an1an2anna22……..…….a2n………………….ann…...an1…...a32a31a22a21a11k=01234ki(i1)/2j1,ijn(n-1)/2n(n+1)/2-1按行序为主序:
a11a2100……..0a220……..0an1an2an3……..………………….0annijLoc(a)=Loc(a11+(j-1)]*l2ann…...an1…...a32a31a22a21a11k=01234)+[(i(i-1)n(n-1)/2n(n+1)/2-1按行序为主序:三角矩阵的压缩存储
00…an-1,n-200……0…………….a120a1100……………a22a23a210a340………a32a330an-1,n-1an,n-1an-1,nann……………………………Loc(aij)=Loc(a11)+2(i-1)+(j-1)annann-1…...…...a23a22a21a12a11k=012343n-2按行序为主序:对角矩阵的压缩存储
前面的例子中有3条非0元素(m=3),元素个数为3*n-2;
东华理工学院程朋根十字链表法(3)稀疏矩阵
三元组表所需存储单元个数为3(t+1)其中t为非零元个数8761221931-3131463243418251516-746M.datae012345678data[0].i,data[0].j,data[0].e分别存放矩阵行列维数和非零元个数行列下标ij非零元值00009012000000014000030M00002400000000180067070150稀疏矩阵的压缩存储方法
(4)稀疏矩阵抽象数据类型定义
(4)稀疏矩阵抽象数据类型定义(续)
(5)三元组顺序表示法
(6)三元组顺序表示的矩阵转置算法
0002400001800000150070006700000000901200001400003M09T08761221931-3131463243418251516-746ijv012345678Mv8-3151218924-70030015000180120024000007000000001400000000076ij76131621253134466314012345678T?
(6)三元组顺序表示的矩阵转置算法(续)
方法一:按M的列序转置
vji1221931-3131463243418251516-746vji-3311561121218529132443-7641436原矩阵M转置矩阵TM中(3,1,-3)、(6,1,15)的顺序和T中(1,3,-3)(1,6,15)顺序一致
8761221931-3131463243418251516-746ijv012345678m867-3311561121218529132443-7641436ijv012345678tkppppppppkkkkppppppppcol=1col=2
算法5.1求稀疏矩阵M的转置矩阵TStatusTransposeSMatrix(TSMatrixM,TSMatrix&T){ T.mu=M.nu; T.nu=M.mu; T.tu=M.tu; if(T.tu){ q=1; for(col=1; col<=M.nu; ++col)for(p=1; p<=M.tu; ++p)if(M.data[p].j==col){ T.data[q].i=M.data[p].j; T.data[q].j=M.data[p].i; T.data[q].e=M.data[p].e; ++q; } } returnOK; } 第45页:方法二:快速转置
方法二:快速转置0即按M中三元组次序转置,转置结果放入T中恰当位置0此法关键是要预先确定M中每一列第一个非零元在T中位置0为确定这些位置,转置前应先求得M的每一列中非零元个数0设置num和cpot两个向量,num[col]表示矩阵M中第col列非零元素的个数,cpot[col]指示M中第col列的第一个非零元素在T中的恰当位置0其中:cpot[1]=1cpot[col]=cpot[col-1]+num[col-1]算法5.2的思路
第46页:快速转置的num与cpot
7654321col0101222num[col]9887531cpot[col]0009120000014000000024000001800700000006700001503M算法5.2的思路vji1221931-3131463243418251516-746
第47页:算法5.2快速转置
//采用三元组顺序表存储表示,求稀疏矩阵M的转置矩阵T
- StatusFastTransposeSMatrix(TSMatrixM,TSMatrix&T){T.mu=M.nu;T.nu=M.mu;T.tu=M.tu;if(T.tu){for(col=1;col<=M.nu;++col)num[col]=0;for(t=1;t<=M.tu;+ +t)++num[M.data[t].j];//求M中每一列含非零元个数cpot[1]=1;//求第col列中第一个非零元在T(b.data)中的序号for(col=2;col<=M.nu;++col)cpot[col]=cpot[col-1]+num[col-1];算法5.2
第48页:快速转置续:元素放置
for(p=1;p<=M.tu;++p)col=M.data[p].j;{q=cpot[col];//col为M中的列号,q为当前数据(M.data[p])在T中的顺序号T.data[q].i=M.data[p].j;T.data[q].j=M.data[p].i;T.data[q].e=M.data[p].e;++cpot[col];}//for}//ifreturnOK;//时间复杂度为O(nu+tu),
- }//当tu和mu*nu接近时,时间复杂度为O(mu*nu)算法5.2(续)
第49页:快速转置过程示意
8761221931-3131463243418251516-746ijv012345678maijv012345678mb867-3311561121218529132443-76414367654321col0101222num[col]9887531cpot[col]pppppppp9246357
第50页:稀疏矩阵转置应用程序
稀疏矩阵的转置算法应用程序
第51页:行逻辑链接的顺序表
(7)行逻辑链接的顺序表
- 为了便于随机存取任一行的非零元素,需要知道每一行非零元素在三元组表中的位置,方法是将上述方法的rpot保存在稀疏矩阵的存储结构中,具体为:
- Typedefstruct{Tripledata[MAXSIZE+1];//非零元三元组表intrpos[MAXRC];//各行第一个非零元的位置表intmu,nu,tu;
- }
第52页:稀疏矩阵相乘思路
矩阵相乘
- 稀疏矩阵相乘:找到M中的j值和N中的i值相等的元素相乘即可,即(i,k,M(i,k))与(k,j,N(k,j))相乘。
- 为了快速找到N中对应的i值,设置rpos[]可以提高速度ni1Q(i,j)M(i,k)N(k,j)vji221112-2134234321row5321rpos[row]
第53页:稀疏矩阵相乘的累计和
稀疏矩阵相乘时,对M中的M.data[p]在N中寻找所有满足M.data[p].j=N.data[q].i条件的N.data[q],并求M.data[p].v和N.data[q].v的乘积;这个乘积只是乘积矩阵Q(i,j)中的一部分,为此需要设置一个累计和变量ctemp[],其初值为零:ctemp[] =0;
- 稀疏矩阵相乘积不一定是稀疏矩阵
第54页:算法5.3矩阵相乘
vji311541-122根2学1院程朋东3华理工算法5.3StatusMultSMatrix(RLSMatrixM,RLSMatrixN,RLSMatrix&Q){ if(M.nu!=N.mu)returnERROR; Q.mu=M.mu; Q.nu=N.nu; Q.tu=0;//Q是非零矩阵for(arrow=1; arow<=M.mu; ++arrow){Q.rops[arrow]=Q.tu+1;p<M.rpos[arrow+1]; ++p){ brow=M.data[p].j;else{ t=N.tu +1} 第55页:算法5.3续:压缩存储结果
算法5.3(续)for(q=N.rpos[brow];q<t;++q){ccol=N.data[q].j//乘积元素在Q中列号ctemp[ccol]+=M.data[p].e*N.data[[q].e;}//forq}//forq,求得Q中第crow(=arow)行的非零元for(ccol=1;ccol<=Q.nu;++ccol)//压缩存储该行非零元if(ctemp[cool]){if(++Q.tu>MAXSIZE)returnERROR;Q.data[Q.tu]={arrow,ccol,ctemp[ccol]};}//if}//forarrow}//ifreturnOk;
- }//MultSMatrix
第56页:十字链表的提出
(8)十字链表
- 当矩阵的非零元素个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表
- 例如:两个矩阵相加时,非零元素的插入会使线性表中的元素移动,此时用链式存储结构表示三元组的线性表更为恰当
- 链表中,一个结点含5个域:行号、列号、非零元的值、右链指针,下链指针
第57页:十字链表结点结构
结构设计为:
- typedefsstructOLNode{intElemtypei,j ;//该非零元的行和列下标e;StructOLNode*right,*down ;//该非零元所在行表和列表的后继链域
- }OLNode;*Olink;
- typedefsstruct{Olink*rhead,*chead;//行和列链表头指针向量基址由CreatSMatrix分配intmu,nu,tu ;//稀疏矩阵的行数、列数和非零元个数
- } Crosslist;ejirightdown
第58页:算法5.4创建稀疏矩阵
算法5.4创建稀疏矩阵 StatusCreatSMatrix_OL(Crosslist&M){ if(M)free(M); Scanf ( &m ,&n, &t ) ;M.nu:=n; M.tu:=t; if(!(M..rhead=(Olink*)malloc((m+1)*sizeof(Olink))))exit(OVERFLOW); if(!(M.chead=(Olink*)malloc((n+1)*sizeof(Olink))))exit(OVERFLOW); M.rhead[ ]=M.chead[ ]=NULL; 第59页:算法5.4续:结点插入
for(scanf(&i,&j,&e); i!=0; scanf(&i,&j,&e)){P->i=i; P->j=j; P->e=e;else{(q->right)&&q->right->j<j; q=q->right; )p->right=q->right; q->right=p; }else{(q->down)&&q->down->i<i; q=q->down; )p->down=q->down; } returnOk; q->down=p; }} 第60页:十字链表创建实例
814^^432^^m=4,n=31,1,32,2,52,3,44,1,82,1,7113^^217^^225^^04043083000500A创建稀疏矩阵—实例
第61页:第四节广义表的定义与存储结构
第四节广义表的定义与存储结构
第62页:广义表的术语
(1)广义表的术语
- 广义表是线性表的推广,广泛应用于人工智能领域的LISP与语言
- 广义表一般记作LS=(1,2,…,n),其中LS为广义表(1,2,…,n)的表名,n是它的长度
- 线性表与广义表的区别:
- 线性表的元素只限于单个元素
- 广义表的元素可以是单个元素、也可以是广义表,并分别成为广义表LS的原子或子表
- 当广义表非空时,第一个元素1为表头(head),其余元素(2,…,n)组成表尾(Tail)
第63页:广义表举例
(2)广义表举例
- A= (),A是空表,表长为0
- B=(e),列表B只有一个原子e,长度为1
- C=(a,(b,c,d)),列表C长度为2,有一个原子a和一个子表(b,c,d)
- D=(A,B,C),列表D的长度为3,三个元素都是列表,显然D=((),(e),(a,(b,c,d)))
- E=(a,E),列表E是一个递归表,长度为2,相当于(a,(a,(a,…)))BCeaDAbcd
第64页:广义表的结构特点
结论:Bea
- 列表的元素可以是子表,而子表的元素还可以是子表,是一个多层次的结构;
- 列表可为其他列表所共用,并通过子表名来引用,例如,D可以不必列出子表的值,而直接通过子表A,B,C名称来引用;
- 列表可以是一个递归表;
- m元多项式表示是典型实例
- 注意表()与表(())的不同:前者为空表,长度为零;后者长度为1,可以分解成表头表尾均为空表()DACbcd
第65页:ADTGlist的定义
(3)抽象数据类型广义表定义
- ADTGlist{
- 数据对象:D={ei|i=1,2,…,n;n≥0;eiAtomset或eiGlist,Atomset为某个数据元素}
- 数据关系:R= {<ei-1,ei>|ei-1,eiD, 2≤i≤n-2}
- 基本操作:InitGList(&L)//创建一个空广义表CreateGList(&L,S)//由S创建广义表CreateGList(&L,S)//销毁广义表GListLength(L)//求广义表的长度,即元素的个数GetHead(L)//得到广义表L的头InsertFirst(&L,e)//插入元素作为广义表L的第一个元素…………
- } ADTGLIst
第66页:广义表的存储结构
(4)广义表的存储结构
- 广义表的数据元素具有不同的数据结构,难以用顺序存储结构来表示,通常采用链式存储结构
- 表中的元素分原子和列表,结点分表结点、原子结点
- 表结点包括:标志域、表头指针、表尾指针
- 原子结点包含:标志域、值域
第67页:头尾链表存储表示
结构一:头尾链表存储表示
- Typedefenum{ATOM,LIST}ElemTag;ATOM==0原子,LIST==1子表
- TypedefstructGLNode{ElemTagtag;
- Union{AtomTypeatom;struct{structGLNode*hp,*tp;}ptr;//ptr是表结点的指针域,ptr.hp和ptr.tp分别志向表头和表尾
- };
- }*Glist;(4)广义表的存储结构(续)tag=0atomtphptag=1
第68页:头尾链表存储实例
A=NULLB10eC110a1110b0c0dD111E110a
- 除空表的表头指针为空外,对任何非空列表,其表头指针均指向一个表结点
- 容易分清列表中原子和列表的层次
- 最高层次结点个数即为列表的长度BCeaDAbcd
第69页:扩展线性链表存储表示
结构二:扩展线性链表存储表示
- Typedefenum{ATOM,LIST}ElemTag;ATOM==0原子,LIST==1子表
- TypedefstructGLNode{
- ElemTagtag;
- Union{AtomTypeatom;structGLNode*hp;
第70页:本章重点
本章重点
- 数组的定义、特点
- 数组的顺序表示
- 稀疏矩阵与表示方法
- 广义表的定义与存储结构
第71页:课堂练习
课堂练习:
- 1、一维数组和线性表的区别是:前者长度固定,后者的长度可变。
- 2、对数组进行的两种操作是:查找和修改。
- 3、数组中,每个元素的长度为3个字节,行下标i从1到8,列下标j从1到10,从首地址SA开始连续存放在存储器内。该数组按行存放时,A[8][5]的起始地址为:SA+((8-1)*10+(5-1))*3=SA+222。
- 5、稀疏矩阵一般的压缩存储方法有两种:三元组和十字链表。
- 6、广义表((a,b),c,d)的表头是:(a,b),表尾是:(c,d)。
- 7、广义表((a),((b),c),(((d))))的长度是:3,深度是:4。
第72页:习题(一)
习题:
- 1、一维数组和线性表的区别是:前者长度固定,后者的长度可变。
- 2、对数组进行的两种操作是:查找和修改。
- 3、数组中,每个元素的长度为3个字节,行下标i从1到8,列下标j从1到10,从首地址SA开始连续存放在存储器内。该数组按行存放时,A[8][5]的起始地址为:SA+((8-1)*10+(5-1))*3=SA+222。该数组按列存放时,A[5][8]的起始地址为:SA+((8-1)*8+(5-1))*3=SA+180。
- 4、设矩阵A是对称矩阵,为了节省次、存储空间,将其下三角部分按行序存放在一维数组B[1,n(n-1)/2]中,对任一下三角元素aij(i>=j),在一维数组B的下标位置k的值是:i(i-1)/2+j。
第73页:习题(二)
5、稀疏矩阵一般的压缩存储方法有两种:三元组和十字链表。
- 6、广义表((a,b),c,d)的表头是:(a,b),表尾是:(c,d)。
- 7、广义表((a),((b),c),(((d))))的长度是:3,深度是:4。
- 8、假设稀疏矩阵A采用三元组表示,编写一个函数计算其转置矩阵B,要求B也采用三元组表示。习题:
下载地址:{{downurl}}
{{{a}}}
{{#b}}{{{b}}}
{{/b}} {{/title}} {{#nolog}}登陆注册
{{/nolog}} {{#djsx}}点我刷新
{{/djsx}} {{#gocz}} {{/gocz}} {{#ffqr}} {{/ffqr}}