1 / 66

第五章 数组和广义表

第五章 数组和广义表. 5.1 数组的类型定义. 5.2 数组的顺序表示和实现. 5.3 矩阵的压缩存储. 5.4 广义表的类型定义. 5.5 广义表的存储结构. 5.1 数组的类型定义. 数组的定义. 数组是由一组 类型相同 的数据元素构成的 有序 集合,每个数据元素称为一个数组元素(简称为元素),每个元素受 n ( n ≥1) 个 线性关系 的约束, 每个元素在 n 个线性关系中的序号 i 1 、 i 2 、 … 、 i n 称为该元素的下标,并称该数组为 n 维数组。. 数组的特点. 元素本身可以具有某种结构,属于同一数据类型;

adin
Download Presentation

第五章 数组和广义表

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五章 数组和广义表 5.1 数组的类型定义 5.2 数组的顺序表示和实现 5.3 矩阵的压缩存储 5.4 广义表的类型定义 5.5广义表的存储结构

  2. 5.1 数组的类型定义 数组的定义 数组是由一组类型相同的数据元素构成的有序集合,每个数据元素称为一个数组元素(简称为元素),每个元素受n(n≥1)个线性关系的约束,每个元素在n个线性关系中的序号i1、i2、…、in称为该元素的下标,并称该数组为 n 维数组。 数组的特点 • 元素本身可以具有某种结构,属于同一数据类型; • 数组是一个具有固定格式和数量的数据集合。

  3. 数组示例 a11 a12 … a1n a21 a22 … a2n … … … … am1 am2 … amn A= 例如,元素a22受两个线性关系的约束,在行上有一个行前驱a21和一个行后继a23,在列上有一个列前驱a12和和一个列后继a32。

  4. A=(A1,A2,……,An) 其中: Ai=(a1i,a2i,……,ami) (1≤i≤n) 数组——线性表的推广 a11 a12 … a1n a21 a22 … a2n … … … … am1 am2 … amn A= 二维数组是数据元素为线性表的线性表。

  5. 在数组中插入(或)一个元素有意义吗? x a11 a12 … a1n a21 a22 … a2n … … … … am1 am2 … amn a11 a12 … a1n a21 a22 … a2n … … … … am1 am2 … amn A= A= 数组的基本操作 将元素 x 插入 到数组中第1行第2列。 删除数组中 第1行第2列元素。

  6. 数组的基本操作 ⑴ 存取:给定一组下标,读出对应的数组元素; ⑵ 修改:给定一组下标,存储或修改与其相对应的数组元素。 存取和修改操作本质上只对应一种操作——寻址 数组应该采用何种方式存储? 数组没有插入和删除操作,所以,不用预留空间,适合采用顺序存储。

  7. 数组的类型定义 ADT Array { 数据对象: D={aj1,j2, ...,,ji,jn| ji =0,...,bi -1, i=1,2,..,n } 数据关系: R={R1, R2, ..., Rn} Ri={<aj1,... ji,... jn , aj1, ...ji +1, ...jn > | 0  jk  bk -1, 1  k  n 且k  i, 0  ji bi -2, i=2,...,n } } ADT Array

  8. 基本操作: InitArray(&A, n, bound1, ..., boundn) DestroyArray(&A) Value(A, &e, index1, ..., indexn) Assign(&A, e, index1, ..., indexn)

  9. InitArray(&A, n, bound1, ..., boundn) 操作结果:若维数 n 和各维长度合法, 则构造相应的数组A,并 返回OK。 DestroyArray(&A)操作结果:销毁数组A。

  10. Value(A, &e, index1, ..., indexn) 初始条件:A是n维数组,e为元素变量, 随后是n 个下标值。 操作结果:若各下标不超界,则e赋值为 所指定的A 的元素值,并返 回OK。

  11. Assign(&A, e, index1, ..., indexn) 初始条件:A是n维数组,e为元素 变量,随后是n 个下标值。操作结果:若下标不超界,则将e的 值赋给所指定的A的元 素,并返OK。

  12. 二维数组的定义: 数据对象: D = {aij | 0≤i≤b1-1, 0 ≤j≤b2-1} 数据关系: R = { ROW, COL } ROW = {<ai,j,ai,j+1> | 0≤i≤b1-2, 0≤j≤b2-1} COL = {<ai,j,ai+1,j> | 0≤i≤b1-1, 0≤ j≤b2-2}

  13. 二维数组的定义:

  14. 类型特点: • (1)只有引用型操作,没有加工型操作; • (2) 数组是多维的结构,而存储空间是 • 一个一维的结构。 • 5.2 数组的顺序表示和实现 • 有两种顺序映象的方式: (1)以行序为主序 (2)以列序为主序

  15. a00 a01 ……. a0n-1 a10 a11 a00 a01 …… a0n-1 …….. a1n -1 a10 a11 …… a1n-1 ………. …………………. am-10 am-10 am-11 … am-1n-1 am-11 …….. am-1n-1 0 1 按行序为主序存放 n-1 n LOC(i,j) = LOC(0,0) + (n×i+j)×L m*n-1

  16. a00 a10 ……. am-10 a00 a01……..a0n-1 a01 a10 a11 ……..a1n-1 a11 …….. …………………. am-11 am-10am-11… am-1n-1 ………. a0n-1 a1n-1 …….. am-1n-1 0 1 按列序为主序存放 m-1 m LOC(i,j) = LOC(0,0) + (m×j+i)×L m*n-1

  17. 二维数组A中任一元素ai,j的存储位置 LOC(i,j) = LOC(0,0) + (n×i+j)× L 二维数组A中任一元素ai,j的存储位置 LOC(i,j) = LOC(0,0) + (m×j+i)× L 以“行序为主序”的存储映象: 称为基地址或基址 以“列序为主序”的存储映象:

  18. 推广到一般情况,可得到 n 维数组数据元素存储位置的映象关系 n LOC(j1, j2, ..., jn ) = LOC(0,0,...,0) + ∑ ci ji =1 i 其中 cn = L,ci-1 = bi ×ci , 1 < i  n。 称为 n 维数组的映象函数。数组元素 的存储位置是其下标的线性函数。

  19. 5.3 矩阵的压缩存储 5.3.1 特殊矩阵 5.3.2 稀疏矩阵

  20. 特殊矩阵和稀疏矩阵 特殊矩阵:矩阵中很多值相同的元素并且它们的分布有一定的规律。 稀疏矩阵:矩阵中有很多零元素。 压缩存储的基本思想是: ⑴ 为多个值相同的元素只分配一个存储空间; ⑵ 对零元素不分配存储空间。

  21. 以常规方法,即以二维数组表示 高阶的稀疏矩阵时产生的问题: (1) 零值元素占了很大空间; (2) 计算中进行了很多和零值的运算。

  22. 解决问题的原则: (1) 尽可能少存或不存零值元素; (2) 尽可能减少没有实际意义的运算; (3) 操作方便。 即: 能尽可能快地找到与下标值(i,j)对应的元素, 能尽可能快地找到同一行或同一列的非零值元。

  23. 特殊矩阵是指非零元素或零元素的分布有一定规律的矩阵。特殊矩阵是指非零元素或零元素的分布有一定规律的矩阵。 5.3.1 特殊矩阵 • 对称矩阵 元素满足条件 aij=aji 1=<i , j=<n 的n阶矩阵。

  24. a11 a12….… ….. a1n a21a22…….. ……. a2n …………………. an1an2…….. ann …... …... a11 a21 a22 a31 a32 an1 ann k=0 1 2 3 4 n(n-1)/2 n(n+1)/2-1 按行序为主序:

  25. a11 0 0…….. 0 a21 a220…….. 0 …………………. 0 an1 an2 an3…….. ann …... …... a11 a21 a22 a31 a32 an1 ann k=0 1 2 3 4 n(n-1)/2 n(n+1)/2-1 • 三角矩阵 按行序为主序: Loc( aij)=Loc(a11)+[ i*(i-1)/2 +(j-1)]*L

  26. a11a12 0 …………… . 0 a21 a22a230…………… 0 0a32 a33a340……… 0 …………………………… 00… an-1,n-2 an-1,n-1an-1,n 按行序为主序: 00… …an,n-1 ann …... a11 a12 a21 a22 a23 ann-1 ann …... k=0 1 2 3 4 n(n+1)/2-1 • 对角矩阵 Loc(aij)=Loc(a11)+2(i-1)+(j-1)

  27. 5.3.2 稀疏矩阵 假设 m 行 n 列的矩阵含 t 个非零元素,则称 为稀疏因子。 通常认为 0.05 的矩阵为稀疏矩阵。

  28. 稀疏矩阵的压缩存储方法: 一、三元组顺序表 二、行逻辑链接的顺序表 三、十字链表

  29. 一、三元组顺序表 #define MAXSIZE 12500 typedef struct { int i, j; //该非零元的行下标和列下标 ElemType e; // 该非零元的值 } Triple; // 三元组类型 typedef union { Triple data[MAXSIZE + 1]; int mu, nu, tu; } TSMatrix; // 稀疏矩阵类型

  30. i j e 0 1 2 3 4 5 6 7 8 678 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7

  31. 如何求转置矩阵? T

  32. 用常规的二维数组表示时的算法 for (col=1; col<=nu; ++col) for (row=1; row<=mu; ++row) T[col][row] = M[row][col]; 其时间复杂度为: O(mu×nu)

  33. ? i j e i j e 678 768 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 1 2 12 1 3 -3 1 3 9 1 6 15 3 1 -3 2 1 12 3 6 14 2 5 18 4 3 24 3 1 9 5 2 18 3 4 24 6 1 15 4 6 -7 6 4 -7 6 3 14 M.data T.data

  34. 解决思路: 只要做到 将矩阵行、列值互换; 将每个三元组中的i和j相互调换; 重排三元组次序,使T.data中元素以N的行(M的列)为主序

  35. 方法一:按M的列序转置 按T.data中三元组次序依次在M.data中找到相应的三元组进行转置,即按照矩阵M的列序来进行置换。 为找到M中每一列所有非零元素,需对其三元组表M.data从第一行起扫描一遍。由于M.data中以M行序为主序,所以由此得到的恰是T.data中应有的顺序。

  36. p p p p p p p p q p q q q p p p p p p q p i j e i j e 6 78 768 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 1 2 12 1 3 -3 1 3 9 1 6 15 3 1 -3 2 1 12 3 6 14 2 5 18 4 3 24 3 1 9 5 2 18 3 4 24 6 1 15 4 6 -7 6 4 -7 6 3 14 M.data T.data col=1 col=2

  37. Status TransposeSMatix(TSMatrix M,TSMatrix &T){ //采用三元组表存储表示,求稀疏矩阵M的转置矩阵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; } } return OK; }//TransposeSMatrix T(n)=O(nu*tu)

  38. cpot[1]=1; cpot[col]=cpot[col-1]+num[col-1]; (2col M.nu) 方法二:快速转置 按M.data中三元组次序转置,转置结果放入T.data中恰当位置。 此法关键是要预先确定M中每一列第一个非零元在T.data中位置,为确定这些位置,转置前应先求得M的每一列中非零元个数。 实现:设两个数组 num[col]:表示矩阵M中第col列中非零元个数 cpot[col]:指示M中第col列第一个非零元在T.data中位置 显然有:

  39. i j e t t t t t t t t 0 1 2 3 4 5 6 7 8 678 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 Col 1 2 3 4 5 6 7 5 2 18 Num[col] 6 1 15 6 4 -7 cpot[col] 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]; 1 1 1 1 2 2 2 0 0 1 1 3 5 7 8 8 9

  40. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 p p p p p p p p 678 1 2 12 1 3 9 3 1 -3 col 7 3 5 6 4 1 2 3 6 14 M.data T.data num[col] 0 1 0 1 2 2 2 4 3 24 9 cpot[col] 8 5 1 3 7 8 5 2 18 6 1 15 6 4 -7 2 4 6 9 3 5 7 768 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14

  41. 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]; } // for } // if return OK; } // FastTransposeSMatrix T(n)=O(nu+tu) T(n)=O(mu*nu)

  42. 三元组顺序表又称有序的双下标法,它的特点是,非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算。然而,若需随机存取某一行中的非零元,则需从头开始进行查找。三元组顺序表又称有序的双下标法,它的特点是,非零元在表中按行序有序存储,因此便于进行依行顺序处理的矩阵运算。然而,若需随机存取某一行中的非零元,则需从头开始进行查找。

  43. 二、行逻辑链接的顺序表 #define MAXMN 500 typedef struct { Triple data[MAXSIZE + 1]; //非零元三元组表 int rpos[MAXMN + 1]; //各行第一个非零元的位置表 int mu, nu, tu; } RLSMatrix; // 行逻辑链接顺序表类型

  44. i j e 0 1 2 3 4 5 6 7 8 678 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 row 2 3 1 4 6 5 rpos[row] 3 3 5 6 1 7

  45. M= N= Q= Q = M  N

  46. 矩阵乘法的精典算法: for (i=1; i<=m1; ++i) for (j=1; j<=n2; ++j) { Q[i][j] = 0; for (k=1; k<=n1; ++k) Q[i][j] += M[i][k] * N[k][j]; } 其时间复杂度为: O(m1×n2×n1)

  47. N.data i j e i j e i j e Q.data M.data 1 2 3 4 1 2 3 4 1 2 3 4 1 1 3 1 2 2 2 1 1 1 4 5 3 1 -2 2 2 -1 3 2 4 3 1 2 ccol 1 2 arow 1 2 3 rops[arow] 1 3 4 p p q q q p p ctemp =5 brow 1 2 3 4 rops[brow] 1 2 3 5 tp t t t tp tp 1 2 6 1 2 1 -1 3 2 4 2 1 -1 4 6

  48. 两个稀疏矩阵相乘(QMN) 的过程可大致描述如下: Q初始化; if Q是非零矩阵 { // 逐行求积 for (arow=1; arow<=M.mu; ++arow) { // 处理M的每一行 ctemp[] = 0; // 累加器清零 计算Q中第arow行的积并存入ctemp[] 中; 将ctemp[] 中非零元压缩存储到Q.data; } // for arow } // if

  49. Status MultSMatrix (RLSMatrix M, RLSMatrix N, RLSMatrix &Q) { if (M.nu != N.mu) return ERROR; Q.mu = M.mu; Q.nu = N.nu; Q.tu = 0; if (M.tu*N.tu != 0) { // Q是非零矩阵 for (arow=1; arow<=M.mu; ++arow) { // 处理M的每一行 } // for arow } // if return OK; } // MultSMatrix

More Related