1 / 86

第五章 数组 ( Array) 和广义表

第五章 数组 ( Array) 和广义表.  数组的定义 数组的表示和实现 矩阵的压缩存储 广义表的定义 广义表的存储结构.  主要介绍 多维数组 的概念及在计算机中的存放, 特殊矩阵 的压缩存储及相应运算, 广义表 的概念和存储结构。  通过本章学习, 要求掌握 : 多维数组 的定义及在计算机中的存储表示; 对称矩阵 、 三角矩阵 等特殊矩阵在计算机中的压缩存储表示及地址计算公式; 稀疏矩阵 的 三元组 表示及转置算法实现; 稀疏矩阵 的 十字链表 表示及相加算法实现; 广义表 存储结构表示。. 5.1 数组的定义. ADT Array {

talasi
Download Presentation

第五章 数组 ( Array) 和广义表

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. 第五章 数组(Array)和广义表 数组的定义 数组的表示和实现 矩阵的压缩存储 广义表的定义 广义表的存储结构

  2. 主要介绍多维数组的概念及在计算机中的存放,特殊矩阵的压缩存储及相应运算,广义表的概念和存储结构。主要介绍多维数组的概念及在计算机中的存放,特殊矩阵的压缩存储及相应运算,广义表的概念和存储结构。 通过本章学习,要求掌握: • 多维数组的定义及在计算机中的存储表示; • 对称矩阵、三角矩阵等特殊矩阵在计算机中的压缩存储表示及地址计算公式; • 稀疏矩阵的三元组表示及转置算法实现; • 稀疏矩阵的十字链表表示及相加算法实现; • 广义表存储结构表示。

  3. 5.1 数组的定义 ADTArray{ 数据对象:ji=0, …, bi-1, i=1, 2, …, n, D={aj1j2…jn|n(>0)为数组的维数,bi为数组第i维的长度, ji是数组元素的第i维下标, aj1j2… jnElemSet} 数据关系:R={R1, R2, … , Rn} Ri={<aj1j2…jk…ji…jn, aj1j2…jk…ji+1…jn>| 1  jk  bk-1, 1  k  n 且 k  i, 1  ji  bi-2, aj1j2…jk…ji…jn, aj1j2…jk…ji+1…jnD, i=2, …, n} 基本操作:… }ADTArray

  4. m j n i aij aij aij, ai+1 j ai j, ai j+1 例:二维数组 ADTArray{ 数据对象:j1=0, …, b1-1, j2=0, …, b2-1 D={aj1j2|aj1j2ElemSet} 数据关系:R={R1, R2} R1={<aj1 j2, aj1+1 j2> | 1  j1  b1-2, 1  j2  b2-1, aj1 j2, aj1+1 j2 D} R2={<aj1 j2, aj1 j2+1> | 1  j1  b1-1, 1  j2  b2-2, aj1 j2, aj1 j2+1D} 基本操作:… }ADTArray

  5. 例:二维数组 ADTArray{ 数据对象:i=0, …, m-1, j=0, …, n-1 D={aij|aijElemSet} 数据关系:R={R1, R2} R1={<aij, ai+1 j> | 1  i m-2, 1  j  n-1, aij,ai+1 jD} R2={<aij, aij+1> | 1  i m-1, 1  j  n-2, aij,ai j+1D} 基本操作:… }ADTArray

  6. ( ) a00 a01 a02 … a0,n-1 a10 a11 a12 … a1,n-1 … … … … am-1,0 am-1,1 am-1,2 … am-1,n-1 ( ) 列向量形式的线性表 行向量形式的线性表 ( ) 5.1 数组的定义 • 一维数组 • 有限个具有相同类型的变量组成的序列。 • 定长的线性表(别名向量) • 若其中每个变量本身是一维数组(定长的线性表,则构成二维数组。 (a1, a2, a3, …, an)

  7. 5.1 数组的定义 • 数组的特点 • 每个数据元素可以又是一个线性表结构。 • 数组结构可以简单地定义为 • 若线性表中的数据元素为非结构的简单元素,则称为一维数组,即为向量;———定长的线性表 • 若一维数组中的数据元素又是一维数组结构,则称为二维数组;——定长线性表,数据元素是行/列向量形式的定长线性表 • 依次类推,若二维数组中的元素又是一个一维数组结构,则称作三维数组。 • 结论 • 线性表结构是数组结构的一个特例,而数组结构又是线性表结构的扩展。

  8. 5.2 数组的顺序表示和实现 • 对数组的运算,通常有如下两个: • 给定一组下标,存取相应的数组元素 • 给定一组下标,修改相应的元素值 • 由于这两个运算在内部实现时都需要计算出给定元素的实际存储地址,因此,计算数组元素地址这一运算就成了数组中最基本的运算。

  9. a00a01… a0,n-1 a10a11… a1,n-1 a20a21…a2,n-1 … … am-1,0am-1,1…am-1,n-1 a00a10 … am-1,0 a01a11 … am-1,1 a02a12… am1,2 … … a0,n01a1,n-1…am-1,n-1 数组的顺序存储 右边的下标比左边的下标变化快 • 行优先:逐行地顺序存储各元素,在PASCAL,C, COBOL等语言中均采用这种存储方式。 • 列优先:逐列地顺序存储各元素, FORTRAN语言 中采用的是这种方法。 左边的下标比右边的下标变化快

  10. a00 a01 a02 … a0j … a0,n-1 a10 a11 a12 … a1j … a1,n-1 … … … … ai0 ai1 ai2 … aij … ai,n-1 … … … … am-1,0 am-1,1 am-1,2 … am-1,j … am-1,n-1 addr0+ (i*n)*L+j*L 数组元素地址的计算 +0*L +1*L +2*L… +j*L… +(n-1)*L 基址addr0 • 行优先: L——每个数据元素所占据的存储单元数 +0*L +1*L +2*L… +j*L… +(n-1)*L addr0+(1*n)*L Amn= +0*L +1*L +2*L… +j*L… +(n-1)*L addr0+ (i*n)*L addr0+ ((m-1)*n)*L

  11. addr0+ (j*m)*L+i*L 数组元素地址的计算 基址addr0 addr0+(1*m)*L addr0+ (j*m)*L +0*L +1*L … +i*L … +(m-1)*L a00 a01 … a0j … a0,n-1 a10 a11 … a1j … a1,n-1 … … … … ai0 ai1 … aij … ai,n-1 … … … … am-1,0 am-1,1 … am-1,j … am-1,n-1 • 列优先:

  12. LOC( j1, j2, …, jn ) = addr0 + ( j1*b2*b3*…*bn + j2*b3*b4*…*bn+ ……+ jn-1*bn + jn) * L n 维数组地址的计算 • 各维元素个数为 b1 , b2 , b3 , …, bn , 下标为 j1 , j2 , j3 , … , jn的数组元素的存储地址: 存储位置是下标的线性函数。 存取数组中任一元素的时间相等 随机存储结构

  13. 二维数组的定义及基本操作 1、数组结构的定义: #define MAX_ROW_INDEX 10 //行长度 #define MAX_COL_INDEX 10 //列长度 typedef struct { ElemType elem[MAX_ROW_INDEX][MAX_COL_INDEX] ; } ARRAY;

  14. 二维数组的定义及基本操作 2、基本操作——(1)给数组元素赋值 void Assign(ARRAY &A, ElemType elem, int index1, int index2) { //将elem值赋给数组A的index1行index2列的元素 if (index1<0 || index1>=MAX_ROW_INDEX || index2<0 || index2>=MAX_COL_INDEX) exit(ERROR); //若下标超界,出错处理 else A.elem[index1][index2]=elem; }

  15. 二维数组的定义及基本操作 2、基本操作——(2)返回给定位置的元素内容 int Value(ARRAY A, ElemType &elem, int index1, int index2) { if (index1<0 || index1>=MAX_ROW_INDEX || index2<0 || index2>=MAX_COL_INDEX) return ERROR; else { elem= A.elem [index1][index2]; return OK; } }

  16. 5.3 矩阵压缩存储 • 矩阵 • 在很多科学与工程计算中遇到的数学模型。在数学上,矩阵是这样定义的:它是一个由s×n个元素排成的s行(横向)n列(纵向)的表。 • 通常,用高级语言编制程序时,都是用二维数组来存储矩阵元。 • 问题——如何存储矩阵的元,从而使矩阵各种运算有效进行 • 压缩存储——若干元素共用一个存储单元: • 为多个值相同的元只分配一个存储空间; • 对零元不分配空间。 • 选择压缩存储的方法应遵循两条原则: • 尽可能地压缩数据量; • 压缩后仍然可以比较容易地进行各项基本操作。

  17. 5.3 矩阵压缩存储 • 特殊矩阵 • 值相同的元素或零元素在矩阵中的分布有一定规律。 • 类别: • 对称矩阵 • 下(上)三角矩阵 • 对角矩阵 • 稀疏矩阵 • 非零元比零元少,且分布没有一定规律。

  18. 一、特殊矩阵1、对称矩阵 • n阶对称矩阵: aij=aji 1  i, j  n

  19. a21a22 a31a32a33 … … … an1an2 … ann a11 对称矩阵的压缩存储方法 • 一个n×n的方阵,共有n2个元素。 • 对称矩阵中,有n(n-1)/2个元素可通过其他元素获得。 • 如果只存储矩阵的下三角及对角线,则只需n(n+1)/2个元素空间。 a11 a12 … a1,n a21 a22 … a2,n ……… an-1,1 an-1,2 … an-1,n an,1 an,2 … an,n • 设以一维数组sa[0..n(n+1)/2-1]来存储。 0 1 1+2=3 1+2+…+(n-1) 下三角元素: num(i,j)=1+2+3+…+i-1+j-1=i(i-1)/2+j-1 上三角元素: num(i,j)=1+2+3+…+j-1+i-1=j(j-1)/2+i-1 • 即,矩阵中的元素aij与其在数组中的位置k的关系为:

  20. 算法的实现int Value(int A[ ], ElemType &elem, int i, int j)//将aij的值赋给elem { if (i<1 || i>MAX_ROW_INDEX || j<1 || j>MAX_COL_INDEX) return ERROR; else { if (i>=j) k=i*(i-1)/2+j-1; else k=j*(j-1)/2+i-1; elem=A[k]; return OK; } }

  21. 2、三角矩阵 • 下(上)三角矩阵: • 以主对角线为界的上(下)半部分为常数或零,下(上)半部分的元素值没有任何规律。 • 对称矩阵的压缩存储方法也适用于三角矩阵: • n(n+1)/2个元素空间—— 存储矩阵的下(上)三角及对角线; • 加1个存储常数的存储空间。

  22. 3、对角矩阵 • 对角矩阵: • 所有的非零元素都集中在以主对角线为中心的带状区域。

  23. a11 a12 a21 a22 a23 a32 a33 a34 a43 a44 a45 … …   ann-1 ann a11 a12 a21 a22 a23 a32 a33a34 … … an,n-1 ann 对角矩阵的压缩存储方法 0 1 0+2=2 3 4 0+2+3*1=5 6 7 0+2+3*(n-2) 3n-3 num(i,j)=2+3(i-2)+(j-i+1)=2i+j-3 |i-j|<=1

  24. 二、稀疏矩阵 • 一个m×n的矩阵,含有t个非零元素,且t远远小于m×n,则将这个矩阵称为稀疏矩阵。 • 存储原则: • 只存储非零元的值,同时存储适当的辅助信息(非零元所在行和列的位置),以迅速确定一个非零元是矩阵中哪一个位置上的元素。 • 三元组表 • 一个非零元由三元组(i, j, aij)确定,其中,i表示行序号,j表示列序号,aij表示非零元素的值,通常将它称为三元;稀疏矩阵由该三元组及矩阵的行列数唯一确定。 • 存储方法: • 顺序存储结构 • 三元组顺序表 • 行逻辑链接的顺序表 • 链式存储结构 • 十字链表

  25. 下标 行 列 值 0 12 0 0 0 5 0 0 0 6 0 0 0 5 0 0 3 0 7 0 0 10 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0 0 0 0 8 0 7 6 9 1 1 2 12 2 1 6 5 3 2 4 6 4 3 2 5 3 5 3 5 6 4 1 7 7 4 4 10 8 6 3 9 7 6 8 9 1、三元组顺序表 • 用顺序存储结构来表示三元组表所得到的压缩存储方法。 • 以行序为主序顺序排列。 #define MAXSIZE 12500 //非0元个数的最大值 typedef struct //三元组结构 { int i, j; //非0元的行下标、列下标 ElemType e; } Triple; typedef struct //三元组表结构 { int mu, nu, tu; //行数、列数、非0元个数 Triple data[MAXSIZE+1]; //三元组表,data[0]未用 } TSMatrix;

  26. 1、返回三元组顺序表表示的稀疏矩阵的元素内容 int Value(TSMatrix M, ElemType &e, int i, int j) //将 e 赋值为矩阵M的第 i 行第 j 列的元素值 操作算法 { if (i<1 || i>mu || j<1 || j>nu) return ERROR;//检查i、j合法性 else { for (p=1; p<=M.tu; p++) if (M.data[p].i==i && M.data[p].j==j) { e=M.data[p].e; return OK; } //找到,赋值 else if (M.data[p].i>i || M.data[p].i==i && M.data[p].j>j) break; } e=0; //找不到,赋值为0 return OK; }

  27. 操作算法 2、输出三元组顺序表表示的稀疏矩阵 void Print(TSMatrix M) { p=1; for (i=1; i<=M.mu; i++) { for (j=1; j<=M.nu; j++) if (p<=M.tu&&M.data[p].i==i&&M.data[p].j==j) printf(“%4d”, M.data[p++].e); //输出非0元素 else printf(“%4d”, 0); //其他,输出为0 printf(“\n”); } }

  28. 矩阵转置的实现算法 • 矩阵转置 • 变换元素的位置,把位于(row,col)位置上的元素换到(col ,row)位置上,即,把元素的行列互换; • 一个m×n的矩阵M,它的转置矩阵T是一个n×m的矩阵。

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

  30. 矩阵转置的步骤及方法 • 矩阵转置的步骤: • 将矩阵的行列值相互交换; • 将每个三元组中的 i 和 j 相互调换,得到一个按列优先顺序排列的三元组表; • 重排三元组之间的次序,得到按行优先顺序排列的三元组表。 • 矩阵转置的方法 • 普通转置法 • 快速转置法

  31. 678 768 i j v i j v 1 2 12 1 3 -3 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 1 3 9 1 6 15 T 3 1 -3 2 1 12 M 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的列序转置。 • 由于M.data以M行序为主序,所以由此得到的恰是T.data应有的顺序。 • 为找到M中某一列的所有非零元素,需对三元组表M.data从第一行起整个扫描一遍,M.nu列需要扫描三元组表M.nu次。

  32. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 mu nu tu 6 1 15 mu nu tu 6 4 -7 6 7 8 col=1 T.mu=M.nu; T.nu=M.mu; T.tu=M.tu; 7 6 8

  33. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1

  34. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3 T.data[q].i=M.data[p].j; T.data[q].j=M.data[p].i; T.data[q].e=M.data[p].e;

  35. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3

  36. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3

  37. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3 1 6 15

  38. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q p 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3 1 6 15

  39. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q p 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 1 3 -3 1 6 15

  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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 6 7 8 7 6 8 col=1 col=2 1 3 -3 1 6 15 2 1 12

  41. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12

  42. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 6 7 8 7 6 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18

  43. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18

  44. 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 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 6 7 8 7 6 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9

  45. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24

  46. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7

  47. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14

  48. i j e i j e 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 q 1 2 12 1 3 9 3 1 -3 M T 3 6 4 4 3 24 5 2 18 6 1 15 mu nu tu mu nu tu 6 4 -7 7 6 8 6 7 8 col=1 col=2 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14

  49. 实现算法 Status TransposeSMatrix(TSMatrix M, TSMatrix &T) //采用三元组表存储表示,求稀疏矩阵M的转置矩阵T { T.mu=M.nu; T.nu=M.mu; T.tu=M.tu; //矩阵行列值互换 if(T.tu) //存在非零元 { q=1; //q是矩阵T的指针 for(col=1;col<=M.nu;++col) for(p=1;p<=M.tu;++p)//p是M的指针,扫描所有非零元 if(M.data[p].j==col)//若非零元列值等于当前列,送入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; ++q; //矩阵T的指针下移 } } return OK; }

  50. 算法分析 for(col=1;col<=M.nu;++col) for(p=1;p<=M.tu;++p) • 分析: • 时间复杂度为: T(n)=O(M的列数nu非零元个数tu) • 当非零元个数tu与munu同数量级时,时间复杂度就变为: T(n)=O(munu2) • 该算法只适用于tu<<munu的情况。

More Related