第5章 数组和广义表
数据结构第五章 数组与广义表

压缩存储方法:只需要存储下三角 (含对角线)上的元素。可节省一 半空间。
可以使用一维数组Sa[n(n+1)/2]作为n阶对称矩阵A的存 储结构,且约定以行序为主序存储各个元素,则在Sa[k]和矩
阵元素aij之间存在一一对应关系: (下标变换公式)
i(i+1)/2 + j 当i≥j k = j(j+1)/2 + i 当i<j
q = cpot[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; ++cpot[col]; }
分析算法FastTransposeSMatrix的时间 复杂度:
for (col=1; col<=M.nu; ++col) … … for (t=1; t<=M.tu; ++t) … … for (col=2; col<=M.nu; ++col) … … for (p=1; p<=M.tu; ++p) … …
//对当前行中每一个非零元
处
brow=M.data[p].j;
理
if (brow < N.nu ) t = N.rpos[brow+1];
M
else { t = N.tu+1 }
的
for (q=N.rpos[brow]; q< t; ++q) { ccol = N.data[q].j; // 乘积元素在Q中列号
一、三元组顺序表
对于稀疏矩阵,非零元可以用三元组表示, 整个稀疏矩阵可以表示为所有非零元的三元组所 构成的线性表。例如:
数组和广义表

InitArray(&A, n, bound1, ..., boundn) 操作结果:若维数 n 和各维长度合法,
则构造相应的数组A,并 返回OK。
2013年7月14日星期日
DestroyArray(&A) 操作结果:销毁数组A。
2013年7月14日星期日
Value(A, &e, index1, ..., indexn) 初始条件:A是n维数组,e为元素变量, 随后是n 个下标值。 操作结果:若各下标不超界,则e赋值为
2013年7月14日星期日
a
a1 11 a1 21 a1 31 a1 41
a
三维数组元素的标号由三个数字表示,即行、列、纵三个 方向。a142 表示第1行,第4列,第2纵的元素。如果对A3×4×2
(下标从1开始)采用以行为主序的方法存放,即行下标变
化最慢,纵下标变化最快,则顺序为: a111,a112,a121,a122, …,a331,a332,a341,a342 采用以列为主序的方法存放, 即纵下标变化最慢, 行下 标变化最快, 则顺序为:
同理,三维数组最多可有三个直接前驱和三个直接后继, 三维以上数组可以作类似分析。因此,可以把三维以上 的数组称为多维数组,多维数组可有多个直接前驱和多 个直接后继,故多维数组是一种非线性结构。
2013年7月14日星期日
数组的抽象类型定义
ADT Array { 数据对象: D={aj ,j , ...,,j ,j | ji =0,...,bi -1, i=1,2,..,n } 数据关系: R={R1, R2, ..., Rn} Ri={<aj ,... j ,... j , aj , ...j +1, ...j > | 0 jk bk -1, 1 k n 且k i, 0 ji bi -2, i=2,...,n }
《数据结构与算法》第五章-数组和广义表学习指导材料

《数据结构与算法》第五章数组和广义表本章介绍的数组与广义表可视为线性表的推广,其特点是数据元素仍然是一个表。
本章讨论多维数组的逻辑结构和存储结构、特殊矩阵、矩阵的压缩存储、广义表的逻辑结构和存储结构等。
5.1 多维数组5.1.1 数组的逻辑结构数组是我们很熟悉的一种数据结构,它可以看作线性表的推广。
数组作为一种数据结构其特点是结构中的元素本身可以是具有某种结构的数据,但属于同一数据类型,比如:一维数组可以看作一个线性表,二维数组可以看作“数据元素是一维数组”的一维数组,三维数组可以看作“数据元素是二维数组”的一维数组,依此类推。
图5.1是一个m行n列的二维数组。
5.1.2 数组的内存映象现在来讨论数组在计算机中的存储表示。
通常,数组在内存被映象为向量,即用向量作为数组的一种存储结构,这是因为内存的地址空间是一维的,数组的行列固定后,通过一个映象函数,则可根据数组元素的下标得到它的存储地址。
对于一维数组按下标顺序分配即可。
对多维数组分配时,要把它的元素映象存储在一维存储器中,一般有两种存储方式:一是以行为主序(或先行后列)的顺序存放,如BASIC、PASCAL、COBOL、C等程序设计语言中用的是以行为主的顺序分配,即一行分配完了接着分配下一行。
另一种是以列为主序(先列后行)的顺序存放,如FORTRAN语言中,用的是以列为主序的分配顺序,即一列一列地分配。
以行为主序的分配规律是:最右边的下标先变化,即最右下标从小到大,循环一遍后,右边第二个下标再变,…,从右向左,最后是左下标。
以列为主序分配的规律恰好相反:最左边的下标先变化,即最左下标从小到大,循环一遍后,左边第二个下标再变,…,从左向右,最后是右下标。
例如一个2×3二维数组,逻辑结构可以用图5.2表示。
以行为主序的内存映象如图5.3(a)所示。
分配顺序为:a11 ,a12 ,a13 ,a21 ,a22,a23 ; 以列为主序的分配顺序为:a11 ,a21 ,a12 ,a22,a13 ,a23 ; 它的内存映象如图5.3(b)所示。
数组与广义表

其中:1) 矩阵Am×n看成n个列向量的线性表
2) 每个列向量:αj=(a1j, a2j, a3j, …, amj )(0≤j ≤n-1) 3) ai,j在列方向上有一个前驱ai-1,j, 有一个后继ai+1,j
• 或者,可以看成是一个线性表:A=(a0,a1,……,am-1)
• 其中每个数据元素aj是一个行向量形式的线性表: A
}ADT Array
• • • N维数组含有元素的个数: b1 × b2 × … × bn 第i维的长度: bi 元素下标(j1 , j2, … ,jn),0 ≤ ji ≤ bi -1
5.1 数组示例:
数组的定义
a00 a01 …….. a10 a11 …….. am-1,n-1 …….. a0,n-1 a1,n-1 am-1,n-1
1 2 … i-1 aij
*(A.base + off) = e;
return OK; }
5.3 矩阵的压缩存储 特殊矩阵和稀疏矩阵
特殊矩阵:矩阵中很多值相同的元素并且它们的分布 有一定的规律。 稀疏矩阵:矩阵中有很多零元素。 压缩存储的基本思想是: ⑴ 为多个值相同的元素只分配一个存储空间;
⑵ 对零元素不分配存储空间。
5.3.1 3 6 4 7 8
普通高等教育“十一五”国家级规划教材
设一个系统中二维数组采用行序为主的存储方式,已知二 维数组a[10][8]中每个元素占用四个存储单元,且第一 个数据元素地址是1000,求a[4][5]的存储地址?
解: Loc(a[4][5])=Loc(a[0][0])+(i*m+j)*k =1000+(4*8+5)*4 =1148
L:每个数据元素占用的存储单元
数据结构第5章

第5章:数组和广义表 1. 了解数组的定义;填空题:1、假设有二维数组A 6×8,每个元素用相邻的6个字节存储,存储器按字节编址。
已知A 的起始存储位置(基地址)为1000,则数组A 的体积(存储量)为 288 B ;末尾元素A 57的第一个字节地址为 1282 。
2、三元素组表中的每个结点对应于稀疏矩阵的一个非零元素,它包含有三个数据项,分别表示该元素的 行下标 、 列下标 和 元素值 。
2. 理解数组的顺序表示方法会计算数组元素顺序存储的地址;填空题:1、已知A 的起始存储位置(基地址)为1000,若按行存储时,元素A 14的第一个字节地址为 (8+4)×6+1000=1072 ;若按列存储时,元素A 47的第一个字节地址为 (6×7+4)×6+1000)=1276 。
(注:数组是从0行0列还是从1行1列计算起呢?由末单元为A 57可知,是从0行0列开始!) 2、设数组a[1…60, 1…70]的基地址为2048,每个元素占2个存储单元,若以列序为主序顺序存储,则元素a[32,58]的存储地址为 8950 。
答:不考虑0行0列,利用列优先公式: LOC(a ij )=LOC(a c 1,c 2)+[(j-c 2)*(d 1-c 1+1)+i-c 1)]*L 得:LOC(a 32,58)=2048+[(58-1)*(60-1+1)+32-1]]*2=8950选择题:( A )1、假设有60行70列的二维数组a[1…60, 1…70]以列序为主序顺序存储,其基地址为10000,每个元素占2个存储单元,那么第32行第58列的元素a[32,58]的存储地址为 。
(无第0行第0列元素)A .16902B .16904C .14454D .答案A, B, C 均不对 答:此题(57列×60行+31行)×2字节+10000=16902( B )2、设矩阵A 是一个对称矩阵,为了节省存储,将其下三角部分(如下图所示)按行序存放在一维数组B[ 1, n(n-1)/2 ]中,对下三角部分中任一元素a i,j (i ≤j), 在一维数组B 中下标k 的值是:A .i(i-1)/2+j-1B .i(i-1)/2+jC .i(i+1)/2+j-1D .i(i+1)/2+j3、从供选择的答案中,选出应填入下面叙述 ? 内的最确切的解答,把相应编号写在答卷的对应栏内。
数据结构课件PPT数组和广义表

{ q=1; for (col=1;col<=T.mu;++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; } }
(row) (col) (value)
[0] 1 4 22
[0] 1 5 91
[1] 1 7 15
[1] 2 2 11
[2] 2 2 11
[2] 3 6 28
[3] 2 [4] 3来自6 17 4 -6[3] 4 [4] 4
1 22 3 -6
[5] 4 6 39
[5] 6 2 17
[6] 5 1 91
[6] 6 4 39
cpot[1]=1 cpot[col]=cpot[col-1]+num[col-1]
稀疏矩阵的快速转置(算法5.2)
Status FastTransposeSMatrix(TSMatrix M,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]; cpot[1]=1; for ( col=2;col<=M.nu;++col) cpot[col]=cpot[col-1]+num[col-1]; for (p=1;p<=M.Tu;++p) { col=M.data[p].j; q=cpot[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; ++cpot[col]; } }
大学数据结构课件--第5章 数组和广义表

a 32 a 33 a 34 0 0
a 43 a 44 a 45 0
a 54 a 55 a 56 a 65 a 66
5.3.2 稀疏矩阵
稀疏矩阵的存储:如何表示非零元素的位置信息 1. 三元组表:每个元素用一个三元组(i,j,v)来表示。 i j v
0 1 6 1 1 6 2 3 8 12 9
2
3 4 5 6 7 8
2
5.2 数组的顺序表示和实现
a00 a00 a10 a01 存储单元是一维结构,而数组是个多维结构 , …… …… 则用一组连续存储单元存放数组的数据元素就有 am-1,0 a0,n-1 个次序约定问题。 a01 a10
a11
……
a11
……
二维数组可有两种存储方式: am-1,1 a1,n-1
……
K=
i*n-i(i-1)/2+j-i n(n+1)/2
当 i≤j 当i>j
0 a11 ... a1n-1 ... ... ... ... 0 0 0 an-1n-1
当i ≤ j时,a[i][j]是非零元素, a[i][j]前面有i行,共有n+(n-1)+(n-2)+…(n-(i-1))
=i(n+[n-(i-1)])/2=i*n-i(i-1)/2个元素,a[i][j]前面有j列,共j-i个非零元素,
A m× n
( a10 a11 … a1,n-1 )
=
注:
( … … …… ) ( am-1,0 am-1,2 … am-1,n-1 ) ( ( ( (
① 数组中的元素都具有统一的类型; ② 数组元素的下标一般都具有固定的上界和下界,即数组一旦 被定义,它的维数和维界就不再发生改变; ③ 数组的基本操作简单:初始化、销毁、存取元素和修改元素值
数据结构(C)严蔚敏(数组与广义表)PPT课件

a00
Am×n
=
a10 ...
am-1,0
a01 a11 ...
am-1,1
a02 a12 ...
am-1,2
... a0,n-1
...
a1,n-1
... ...
... am-1,n-1
Data Structure
03.12.2020
Page 5
按行序为主序存放
0
1
n-1
Am×n
=
a00 a10 ...
a00
Am×n
=
a10 ...
am-1,0
a01 a11 ...
am-1,1
a02 a12 ...
am-1,2
... a0,n-1
...
a1,n-1
... ...
... am-1,n-1
列向量
a00
Am×n
=
a10 ...
am-1,0
a01 a11 ...
am-1,1
a02 a12 ...
初始条件:A 是 n 维数组,e 为元素变量,随后是 n 个下标值。 操作结果:若各下标不超界,则e赋值为所指定的A的元素值,并返回OK。
Assign(&A, e, index1, ..., indexn)
初始条件:A 是 n 维数组,e 为元素变量,随后是 n 个下标值。 操作结果:若下标不超界,则将 e 的值赋给A中指定下标的元素。
a00 a10 ……. am-1,1 a01 a11 …….. am-1,1 ………. a0,n-1 a1,n-1 …….. am-1 ,n-1
Page 7
按行序为主序存放
0
Am×n
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一般地,可以借助线性表的概念递归地定 义n维数组: 一个n维数组是一个元素可直接寻址的线性 表 A = ( A1,A2, … ,An) 若Ai 是简单元素(不是数组), 则A是一维数组, 若Ai 是k-1维数组, 则A是k维数组, 其中 i=1,2,…,n, k是大于0的整数。
数组的性质: (1)数组中的数据元素数量固定。一旦定义 了一个数组,它的维数和维界就不能再改 变,只能对数组进行存取元素和修改元素 值的操作; (2)数组中的数据元素具有相同的数据类型; (3)数组中的每个数据元素都和一组唯一的 下标对应; (4)数组是一种随机存储结构,可随机存取 数组中的任意数据元素。
(2)下三角矩阵。 与上面推导类似,下三角矩阵中s[k]和aij之间 的对应关系为 3.对角矩阵的压缩存储(了解) 总而言之,对特殊矩阵如对称矩阵、三角矩 阵、对角矩阵等的压缩方法是:找出这些特 殊矩阵中元素的分布规律,把那些有一定分 布规律的、值相同的元素(包括零元素)压缩存 储到一个存储空间中。这样的压缩存储只需 要在算法中按公式作一个映射,即可实现矩 阵元素的随机存取。
1. 按照列序进行转置 按照表b.data的三元组的次序,依次在表 a.data中找到相应的三元组,然后进行转置, 即按照矩阵M的列序来进行转置。由于M的 列即为N的行,在表a.data中,按列扫描,所 以得到的b.data必按行主序存放。为了找到M 的每一列中所有的非零的元素,每次都必须 从头到尾扫描M的三元组表,算法的C++代码 如下:
(4)对角矩阵:对角矩阵是所有的非零元均 集中在以对角线为中心的带状区域中的n阶 方阵。即除了主对角线上和直接在对角线 上、下方若干条线上的元素之外,所有其 他的元素皆为0。
5.3.2 特殊矩阵的压缩存储 . .
1.对称矩阵的压缩存储 设矩阵An×n是对称的,对称的两个元素可以共用 一个存储单元,这样,原来n阶方阵需n2个存储单 元,如采用压缩存储,仅需n(n+1)/2个存储单元, 节约将近一半存储空间。 将n阶对称方阵存放到一个向量空间s[0]到 s[n(n+1)/2一1]中,并找到s[k]与a[i][j]的一一对应关 系从而使在s[k]中直接访问a[i][j]的方法。
当一个数组的每一个数组元素都含有两个 下标时,该数组称为二维数组。 可以把一个二维数组看成是每个数据元素 都是相同类型的一维数组的一维数组,这 样,也可以把二维数组看作为一个线性表。 依此类推,一个三维数组可以看作是一个 每个数据元素都是相同类型的二维数组的 一维数组。 如图5-l
在C++语言中,一个二维数组可以定义为其 分量类型为一维数组的一维数组类型,即 typedef ElemType Array2 [m][n]; 这个定义等价于 typedef ElemType Arrayl [n]; typedef Arrayl Array2[m]; 即定义了一个长度为m的线性表,表中的每 个元素是一个长度为n的线性表。
2.十字链表的概念和C++类定义 当稀疏矩阵中非零元的位置或个数经常变动 时,三元组就不适合作稀疏矩阵的存储结构 了,此时采用十字链表作为存储结构是一种 较好的方法。在该方法中,每一个非零元用 一个结点表示,结点中除了表示非零元所在 的行、列和值的三元组(i,j,v)外,还需增加 两个链域:行指针域,用来指向本行中下一 个非零元素;列指针域,用来指向本列中下 一个非零元素。
第5章 数组和广义表
数组和广义表可以看成是线性表的推广, 它们与前面讨论的线性结构不同,前面的线 性结构是原子类型的,而数组和广义表的数 据结构是结构化类型的,即元素的值是可以 再分解的。
5.1数组的定义及抽象数据类型表示
5.1.1 数组的定义 . . 数组(Array)是由一组类型相同的数据元素构成的有 数组 限序列,且该有限序列存储在一块地址连续的内存 单元中。数据元素可以是整数、实数等简单类型, 也可以是数组、结构等构造类型。数组元素在数组 中的相对位置由其下标来确定。 若数组只有一个下标,这样的数组称为一维数组, 把数据元素的下标变成线性表中的位序,则一维数 组就是一个线性表。
5.4.2基于三元组表的稀疏矩阵的转置 矩阵转置是一种最简单的矩阵运算。对于一 个m×n的矩阵M,它的转置矩阵N是一个 n×m的矩阵,且N(i,j)=M(j,i),1≤i≤n, 1≤j≤m。很明显,一个稀疏矩阵的转置矩阵 仍然是一个稀疏矩阵。
要实现三元组顺序表示矩阵的转置,只 需实现以下三点: (1)将矩阵的行列值相互交换; (2)将每个三元组中的i和j相互调换; (3)重新排列三元组之间的顺序便可实现矩 阵的转置。 有两种实现稀疏矩阵的转置的方法。 设a和b分别是转置前和转置后的三元组。
(2)只存放上三角部分。对于对称矩阵,除了 可以用下三角形式存放外,还可以用上三角 形式存放,这时a[0][0]存入s[0],a[0][1]存入 s[1],a[0][2]存入s[2],…,如图5-7所示。 这时s[k]与a[i][j] 的对应关系可以按下面方法 推出: 当i≤j时, aij在上三角部分中,前面共有i行, 共有n+(n-1)+…+(n- (i-1)) = i×n-i×(i-1)/2 个元素,而aij是本行第j-i个元素,故k=i×ni×(i-1)/2+j-i,当i>j时,交换i与j即可。故s[k] 与a[i][j]的对应parMatrix a,SparMatrix b) {// a和b分别是转置前和转置后的三元组表 b.rows=a.cols; b.cols=a.rows; b.terms=a.terms; if(b.terms>0) { int bno=0;
for(int col=0;col<a.cols;col++) //按列扫描 for(int ano=0;ano<a.terms;ano++) //对三 元组表扫描 if(a.data[ano].j= =co1) //进行转置 { b.data[bno].j=a.data[ano].i; b.data[bno].i=a.data[ano].j; b.data[bno].v=a.data[ano].v; bno++; }
只要给出一组下标便可求得相应数组元素 的存储位置。下面以行序为主序的存储结 构为例,说明如何由下标计算相应数组元 素的存储地址。 假定每个数据元素占L个存储单元,则二 维数组A中任意元素aij的存储地址由下式确 定 LOC[i,j]=LOC[0,0]+( b2×i+j)×L
其中,LOC[i,j]是aij的存储地址;LOC[0, 0]是a00的存储地址,即二维数组A的起始存 储地址,也称为基址, b2是数组第二维的长 度。 推广到一般情况,就可得到n维数组的数据 元素存储地址的计算公式(知道即可)
5.4.1稀疏矩阵的存储方法 . . 稀疏矩阵的存储方法
1.三元组顺序表 在压缩存放稀疏矩阵非零元的同时,若还 存放此非零元所在的行号和列号,则称为三 元组表法,即称稀疏矩阵可用三元组表进行 压缩存储,然而,它是一种顺序存储(按行优 先顺序存放)。由一个非零元的行号、列号、 值组成一个三元组,整个稀疏矩阵中非零元 的三元组合起来称作三元组表。
5.3.1 特殊矩阵 . . 特殊矩阵通常有以下几种: (1)对称矩阵:矩阵A是一个对称矩阵,当且 仅当对于所有的i和j有A(i,j)= A(j,i)。 (2)上三角矩阵:矩阵A是一个上三角矩阵, 当且仅当i>j时,有A(i,j)=0, 即主对角线的 左下方元素均为零元素的矩阵。 (3)下三角矩阵:矩阵A是一个下三角矩阵, 当且仅当i<j时,有A(i,j)=0,即主对角线的 右上方元素均为零元素的矩阵。
转置矩阵
0 14 0 0 − 5 0 −7 0 0 0 36 0 0 28 0
0 0 14 − 7 0 0 0 0 − 5 0 36 0 0 28 0
用“三元组”表示 0 0 1 2 2 1 4 1 0 3 14 -5 -7 36 28 0 1 1 3 4 2 0 1 2 0 36 14 -7 28 -5
仅以行主序存放分两种方式讨论。 (1)只存放下三角部分。由于对称矩阵关于 对角线对称,故只需存放主对角线及主对角 线以下的元素。这时,a[0][0]存入s[0], a[1][0]存入s[1],a[1][1]存入s[2],…, 如图5-6所示。
从上面的对应关系容易推出:当i≥j时,aij在 下三角部分中,aij前面有i行,共有 1+2+3+…+i个元素,而aij是第i行的第j个元素, 即有k=1+2+3+…+i+j=i(i+1)/2+j;当i<j时,aij 在上三角部分中,但与a对称,故只需在下三 角部分中找aij即可,故只需将i与j交换即可, 即k=j(j+1)/2+i。
十字链表(不采用循环链表 十字链表 不采用循环链表) 不采用循环链表
M.chead
^
M.rhead
0 03
0 35
^^
1 1 -1
^^
2 02
^^
3 0 0 5 0 -1 0 0 2 0 0 0
稀疏矩阵中同一行的非零元通过向右的行指 针链接成一个带表头结点的循环链表。同一 列的非零元也通过列指针链接成一个带表头 结点的循环链表。 为了运算方便,我们规定行、列循环链表的 表头结点和表示非零元的结点一样,也定为 五个域,且规定行、列、域值为0,并且将所 有的行、列链表和头结点一起链成一个循环 链表。 书上图5-9
5.2数组的顺序存储与寻址
数组具有有序性,即数组中每个元素是有序 的,并且元素之间的次序是不能改变的。对 数组的操作除创建和销毁外,只有取数组中某 一元素和修改某一元素的值的操作,没有插入 和删除操作,因此,采用顺序存储结构表示数 组是最好的方式。