1、第五章 数组和广义表 引言:线性表:L=(a1,a2,.,an),ai是同类型的元素,1in 数组: A=(a1,a2,.,an)若ai是同类型的元素,A是一维数组,1in 若ai是同类型的定长线性表,A是多维数组,1in 广义表:Ls=(a1,a,.,an)ai可以是同类型的元素或不定长的线性表,1in 5.1 数组及其操作简单地说,向量和矩阵称为数组。 5.1.1 数组的递归定义 1.一维数组是一个定长线性表(a1,a2,.,an )。其中:ai为元素,i为下标/序号,1in (a1,a2,.,an )又称为向量。,2.二维数组是一个定长线性表(1,2,.,m),其中: i=(ai1,ai
2、2,.,ain)为行向量,1im 由m个行向量组成,记作:,( a11 a12 . a1n ) ( a21 a22 . a2n )( am1 am2 . amn ),Am*n=,即 Am*n=(a11 a12 .a1n),(a21 a22 .a2n),.,(am1 am2 .amn) 或由n个列向量组成,记作:,),),a11 a12 a1na21 a22 a2nam1 am2 amn,),),),),Amxn=,3.三维数组是一个定长线性表( 1,2,.,p )。其中: k=( 1,2,.,m )为定长二维数组,1kp 例 三维数组A13,14,12, p=3, m=4, n=2,a111
3、a112 a121 a122 a131 a132 a141 a142,a211 a212 a221 a222 a231 a232 a241 a242,a311 a312 a321 a322 a331 a332 a341 a342,第1页,第2页,第3页,5.1.2 数组的类型定义和变量说明: 例1 int a10; /10个整数的一维数组char b45; /4行5列个字符的二维数组float c342; /3*4*2个实数的三维数组,A3*4*2 =,5.2数组的顺序表示和实现5.2.1顺序表示(顺序存储结构)1.以行序为主序的顺序存储方式左边的下标后变化,右边的下标先变化2.以列序为主序的
4、顺序存储方式左边的下标先变化,右边的下标后变化 例1 二维数组a13,12,b是首地址,s是元素所占的单元数,a11 a12 a21 a22 a31 a32,序号 内存 地址,1 2 3 4 5 6,1 2 3 4 5 6,序号 内存 地址,b b+s b+2*s b+3*s b+4*s b+5*s,b b+s b+2*s b+3*s b+4*s b+5*s,以行序为主序,以列序为主序,逻辑结构,例2 三维数组a12,13,12,a111 a112 a121 a122 a131 a132,序号 内存 地址,1 2 3 4 5 6 7 8 9 10 11 12,序号 内存 地址,b b+s b+
5、2*s b+3*s b+4*s b+5*s b+6*sb+11*s,b b+s b+2*s b+3*s b+4*s b+5*s b+6*sb+11*s,以行序为主序,以列序为主序,逻辑结构,a211 a212 a221 a222 a231 a232,第1页,第2页,1 2 3 4 5 6 7 8 9 10 11 12,5.2.2数组的映象函数数组元素的存储地址:实现元素的随机存取。例1 一维数组a0n-1设:b为首地址,s为每个元素所占的存储单元数则:元素ai的存储地址:Loc(i)=Loc(0)+i*s=b+i*s 0in-1,下标 0 1 2 i n-1 地址 b b+s b+2*s b+
6、i*s b+(n-1)*s,下标 1 2 3 i n 地址 b b+s b+2s b+(i-1)s b+(n-1)s,例2 一维数组a1n,元素ai的存储地址Loc(i)=Loc(1)+(i-1)*s=b+(i-1)*s 1in 例3 二维数组a1m,1n,假定无零行零列,a11 . a1j . a1n. ai1 . aij . ain. am1 . amj . amn,Amxn=,(1)以行序为主序,aij的地址为Loc(i,j)=Loc(1,1)+(n*(i-1)+j-1)*s=b+(n*(i-1)+j-1)*s 1im,1jn 其中:b为首地址,s为每个元素所占的存储单元数n-列数 m-
7、行数,共i-1行,共j-1列,例3 二维数组a1m,1n,假定无零行零列,a11 a11 . a1j . a1nai1 ai1 . aij . ainam1 am1 . amj . amn,Amxn=,(2)以列序为主序,aij的地址为Loc(i,j)=Loc(1,1)+(m*(j-1)+i-1)*s=b+(m*(j-1)+i-1)*s 1im,1jn 其中:b为首地址,s为每个元素所占的存储单元数n-列数 m-行数,共i-1行,共j-1列,例4 二维数组a0m-1,0n-1(有零行零列),a00 . a0j . a0n-1 a10 . a1j . a1n-1ai0 . aij . ain-1
8、am-10 . am-1j . am-1n-1,Amxn=,(1)以行序为主序,aij的地址为Loc(i,j)=Loc(0,0)+(n*i+j)*s=b+(n*i+j)*s 0im-1,0jn-1 其中:b为首地址,s为每个元素所占的存储单元数n-列数 m-行数,共i行,共j列,例4 二维数组a0m-1,0n-1(有零行零列),a00 a01 . a0j . a0n-1 a10 a11 . a1j . a1n-1. . . ai0 ai1 . aij . ain-1. . am-10 am-11 .am-1j . am-1n-1,Amxn=,(2)以列序为主序,aij的地址为Loc(i,j)=
9、Loc(0,0)+(m*j+i)*s=b+(m*j+i)*s 0im-1,0jn-1 其中:b为首地址,s为每个元素所占的存储单元数n-列数 m-行数,共i行,共j列,例5 三维数组a1p,1m,1n,假定无0页0行0列 1)以行序为主序,akij的地址为Loc(k,i,j)=Loc(1,1,1)+(m*n*(k-1)+n(i-1)+j-1)*s=b+(m*n*(k-1)+n(i-1)+j-1)*s 1kp, 1im, 1jn 其中:b为首地址,s为每个元素所占的存储单元数p-页数 n-列数 m-行数 (2)以列序为主序,akij的地址为Loc(k,i,j)=Loc(1,1,1)+(p*m*(
10、j-1)+p*(i-1)+k-1)*s=b+(p*m*(j-1)+p*(i-1)+k-1)*s 1kp, 1im, 1jn 其中:b为首地址,s为每个元素所占的存储单元数p-页数 n-列数 m-行数,例6 三维数组a0p-1,0m-1,0n-1,假定有0页0行0列 (1)以行序为主序,akij的地址为Loc(k,i,j)=Loc(0,0,0)+(m*n*k+n*i+j)*s=b+(m*n*k+n*i+j)*s 0kp-1, 0im-1, 0jn-1 其中:b为首地址,s为每个元素所占的存储单元数p-页数 n-列数 m-行数 (2)以列序为主序,akij的地址为Loc(k,i,j)=Loc(0,
11、0,0)+(p*m*j+p*i+k)*s=b+(p*m*j+p*i+k)*s 0kp-1, 0im-1, 0jn-1 其中:b为首地址,s为每个元素所占的存储单元数p-页数 n-列数 m-行数,5.3 矩阵的压缩存储 5.3.1 特殊矩阵的压缩存储 特殊矩阵:指非零元素或零元素的分布有一定规律的矩阵。1. n阶对称矩阵1 5 1 3 75 0 8 0 01 8 9 2 6 A为55的对称方阵3 0 2 5 17 0 6 1 3 性质:ai j=aj i 0i, jn-1压缩存储:上三角和下三角对称的两个元素共享一个存储空间设按行顺序存储下三角矩阵元素:a00 a10 a11 a20a21a22
12、an-1,0an-1,1 an-1,n-1下三角矩阵中,第i行(0in)正好有i+1个元素,总数为:(i+1)=n(n+1)/2 需存放元素的数组:sa0n(n+1)/2-1,A=,上三角,下三角,n-1,i=0,为了便于访问对称矩阵中的元素,找ai j与sak间的对应关系:(1) 设ij ,aij在下三角: 第0i-1行共有元素: 1+2+3+i=i(i+1)/2 (个)ai0aij-1共有j个元素 aij的序号为: k=i(i+1)/2+j 0ki(i+1)/2(2) 设ij ,aij在上三角 上三角的aij=下三角的aji,交换i和j 下三角的aji的序号为k=j(j+1)/2+i 0k
13、n(n+1)/2(3) 一般:令I=max(i,j),J=min(i,j),则k与i,j的对应关系统一为:k=I(I+1)/2+J 0kn(n+1)/2aij地址计算公式:LOC(ai j)=LOC(sak)=LOC(sa0+kd) (d:元素占的单元数)=LOC(sa0)+I(I+1)/2+Jd上例:a12和a21均存储在sa4中: k=I(I+1)/2+J=2(2+1)/2+1=4,实现随机存取。,2. 三角矩阵以对角线分上三角矩阵和下三角矩阵:(c为0或相同的常数)a00 a01 . a0,n-1 a00 c cc a11 a1,n-1 a10 a11 c c c . c an-1,n-
14、1 an-1,0 an-1,1. an-1,n-1下三角矩阵 上三角矩阵c可共存储在一个空间中,其余元素的个数:n(n+1)/2, 则,使用数组sa0n(n+1)/2存储元素,其中c存储在最后一个分量中。(1) 上三角矩阵第p行(0pn)有n-p个元素,按行存储aij,aij前的i行一共:(n-p)=i(2n-i+1)/2 在第i行上,aij前刚好有i-j个元素。Aij和sak 的对应关系:k=(2) 下三角矩阵存储与对称矩阵类似k=,i(2n-i+1)/2+j-i 当 ij n(n+1)/2 当 ij,i(i+1)/2+j ij n(n+1)/2 ij,实现随机存取。,3.三对角矩阵,a11
15、 a12 a21 a22 a23a32 a33 a34 . an-2n-3 an-2n-2 an-2n-1an-1n-2 an-1n-1,Anxn=,全0,全0,假定以行序为主,顺序存储非0元素到sa1maxleng:,k=1 2 3 4 5 6 . ? . 3n-2,任意aij0,在sa中的序号: k=(3(i-1)-1)+(j-i+2)=2(i-1)+j,随机存取。,5.3.2 稀疏矩阵的压缩存储1. 稀疏矩阵矩阵Amn中的非0元素的个数s远远小于矩阵元素的总数(sm*n) ,则称A为稀疏矩阵。,0 5 0 0 8 0 3 0 0 0 -2 0 0 0 6 0 0 0 0,A45=,稀疏矩
16、阵压缩存储:只存非0元素;非0元素的确定:三元组( i, j, aij);对压缩存储后的矩阵元素,不能随机存取。 稀疏矩阵压缩存储的方法:顺序存储和链式存储。(只讲顺序存储)2. 三元组表将稀疏矩阵中每个非0元素的三元组按行(或列)次序排列,得到的三元组的线性表,称为三元组表。即:三元组表是稀疏矩阵压缩存储的顺序存储结构,0 5 0 0 8 1 0 3 0 0 0 -2 0 0 0 6 0 0 0 0,A45=,01. a-t-1. MaxSize-1,i j v=aij,A的三元组表,考虑运算的方便,将矩阵的总行数,总列数和非0元素的总个数作为三元组表的属性。,三元组表数据结构定义:#def
17、ine MaxSize 100 /用户自定typedef int DataType; /用户自定typedef struct /三元组int i,j; /行,列号和元素vDataType v; TnTupleNode;typedef struct /三元组表TnTupleNode dataMaxSize;/m,n行列总数和非0元素的总数tint m,n,t; TnTupleTable;,表 a,3. 例子: 下面以稀疏矩阵的转置矩阵为例,说明压缩存储结构如何实现矩阵运算。A的转置矩阵B:,0 1 0 6 5 0 -2 0 0 3 0 0 0 0 0 0 8 0 0 0,B54=,01.b-t-
18、1.MaxSize-1,i j v=aij,B的三元组表,特征:行列数交换:Amn-Bnm元素下标交换:Aij= Bji: A的行是B的列,A的列是B的行。,表 b,问题: (1) 将A矩阵的三元组表中各元素的行列交换得到的三元组表,是否就是其对应的转置矩阵B的按行存储的三元组表? 不是!是对应转置矩阵B的按列存储的三元组表(交换表a中的行列),01. a-t-1. MaxSize-1,i j v=aij,(2)如何由A矩阵的三元组表求对应的转置矩阵B的按行存储的三元组表?即:由表a求表b。(将表a转置成表b)步骤:a.在表a的j列中按顺序找所有列号为j(j初值为0)的三元组;b.将该三元组中
19、的行列号交换后的三元组,依次送入表b的三元组表中。c.列号j加1,jn-1?是,转a;否则结束。,算法:三元组表a转置成三元组表bvoid TransMatrix(TnTupleTable *b, TnTupleTable *a) int p,q,t,col;b-m=a-n; b-n=a-m; b-t=a-t; / 交换行列和非0元素总数if( b-tn; col+) for ( p=0; pt; p+)if ( a-datap.j= =col ) /在j列中找所有0,1,n-1 b-dataq.i=a-datap.j; /将表a的列号j送表b的行中。b-dataq.j=a-datap.i;
20、/将表a的行号i送表b的列中。b-dataq.v=a-datap.v;/送元素的值到b中。q+;,/ 将表a中的列号从0,1,n-1依次找所有的三元组,带行表的三元组表是稀疏矩阵另一种顺序存储结构。见书p65,5.4 广义表(generalized list), 列表(lists) 5.4.1广义表的定义和术语 n(n0)个数据元素或广义表的一个有限序列叫做广义表。记作: LS=(e1,e2,.,en)。 n为LS的长度。其中:LS-广义表名若ei不可再分的项称为原子,约定用小写,1in若ei又是广义表,则称为LS的子表,约定用大写,1in(1)空表 LS=( ),n=0(2)非空表 LS=(
21、e1,e2,.,en) n0其中:e1-LS的表头/首部,记作: head(LS)=e1(e2,.,en)-除表头外,其余的元素构成的表称为 LS的表尾/尾部, 记作:tail(LS)=(e2,.,en)广义表是线性表的推广。,例 (1) M=( ) / 空表 n=0 (2) N=(e) n=1 (3) L=(a,b) n=2 线性表 (4) A=(x,L)=(x,(a,b) n=2 (5) B=(A,y)=( (x,(a,b),y ) n=2 (6) C=(A,B)=(x,(a,b),(x,(a,b),y) n=2 (7) D=(a,D)=(a,(a,() 递归广义表 n=2深度:广义表展开
22、后所含括号的的层数。如:广义表M,N,L,A,B,C,D的深度分别为:1,1,1,2,3,4,(无穷大)。 带有表名的广义表的表示:(1) M( ) (2) N(e) (3) L(a,b) (4)A(x,(a,b) (5)B(x,(a,b),y ) (6) C(x,(a,b),(x,(a,b),y) (7) D(a,D(a,D(),5.4.2 广义表的图型表示非分支结点对应原子。分支结点对应广义表。 例 (1) M=( ) (2) N=(e) (3) L=(a,b) (4)A=(x,L),M,N,e,a,b,L,a,B,A,b,x,L,A,y,b,a,x,L,C,b,A,a,x,L,B,y,D
23、,a,(5)B=(A,y) (6)C=(A,B) (7)D=(a,D),5.4.3 广义表的操作广义表的操作:求表长;求深度;求表头;主要介绍 求表尾;主要介绍求第i个元素和插入等操作。,广义表不仅是线性表的推广,也是树的推广:纯表:与树对应的广义表。特点:不允许表中成分共享和递归。如: (1),(2),(3),(4),(5).再入表:允许有共享结点的表。如:(6):子表A是共享结点,它既是C表的一个元素,又是B表中的一个元素。递归表:允许有递归结点的表。如: (7):D是递归结点,表D是其自身的子表。注:图:具有共享性和递归性的广义表。如: (6)和(7)关系:递归表 再入表 纯表 线性表,
24、任何一个非空广义表的表头是表中的第一个元素,它可以是原子或是子表;表尾是除表头外,其它元素构成的子表。因此它只能是子表。 1.求表头: head(LS)G=(a,G) head(G)=aE=(a,b),c,(d,e) head(E)=(a,b)2.求表尾: tail(LS)G=(a,G) tail(G)=(G)=(a,G)E=(a,b),c,(d,e) tail(E)=(c,(d,e),例子(1) M=( ) / 空表 :不能求表头或表尾。 (2)N=( ); n=1; head(N)=( ) tail(N)=( ) (3) B=(e)head(B)=e tail(B)=( ) (4) C=(
25、a,b,c)head(C)=a tail(C)=(b,c) 不是c和(c)head(Tail(C)=b tail(tail(C)=(c)不是c (5) E=(a,b),c,(d,e)head(E)=(a,b) tail(E)=(c,(d,e)head(Tail(E)=c tail(Tail(E)=(d,e),例子: (1)tail(head(a,b),(c,d) 求运算的结果?=tail(a,b)=(b) (2)已知广义表LS=(a,x,y.z),(b,c),请用head和tail函数取出原子c的运算是什么?head (tail( tail(a,x,y,z),(b,c) )(b,c)(c)c (3) 画出广义表A(a,B(b,A)的图形表示是递归的广义表:,A,a,b,B,分支结点有无穷个,