1 / 50

第五章 多维数组与广义表

第五章 多维数组与广义表. 2007.9. 5.1 多维数组 5.1.1 多维数组的定义 5.1.2 多维数组的存储 5.2 矩阵的压缩存储 5.2.1 特殊矩阵 5.2.2 稀疏矩阵 5.3 广义表. 5.1 多维数组. 5.1.1 多维数组的定义. 一维数组 一维数组可以看成是一个线性表或一个向量,它在计算机内是存放在一块连续的存储单元中,适合于随机查找。 有一个直接前驱和一个直接后继 二维数组 二维数组可以看成是向量的推广。 有两个直接前驱和两个直接后继. 三维数组 最多可有三个直接前驱和三个直接后继 多维数组

chiara
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. 第五章 多维数组与广义表 2007.9

  2. 5.1 多维数组 5.1.1多维数组的定义 5.1.2多维数组的存储 • 5.2 矩阵的压缩存储 5.2.1 特殊矩阵 5.2.2 稀疏矩阵 • 5.3 广义表

  3. 5.1 多维数组

  4. 5.1.1多维数组的定义 • 一维数组 • 一维数组可以看成是一个线性表或一个向量,它在计算机内是存放在一块连续的存储单元中,适合于随机查找。 • 有一个直接前驱和一个直接后继 • 二维数组 • 二维数组可以看成是向量的推广。 • 有两个直接前驱和两个直接后继

  5. 三维数组 • 最多可有三个直接前驱和三个直接后继 • 多维数组 • 把三维以上的数组称为多维数组, • 可有多个直接前驱和多个直接后继 • 是一种非线性结构。

  6. 在C语言中的描述 typedef int datatype; datatype array1[N]; datatype array2[M][N]; datatype array3[X][Y][Z]; 数组一旦被定义,它的维数和维界就不再改变。因此,数组只有存取元素和修改元素值的操作。

  7. 5.2 多维数组的存储 • 考虑问题的基本出发点: • 计算机的内存结构是一维的。因此用一维内存来存多维数组,就必须按某种次序将数组元素排成线性序列。 • 数组一旦建立,结构中的元素个数和元素间的关系就不再发生变化。因此,一般都是采用顺序存储的方法来表示数组。

  8. 两种顺序存储方式 • 行优先顺序——将数组元素按行排列 • 在PASCAL、C语言中,数组就是按行优先顺序存储的。 • 列优先顺序——将数组元素按列向量排列 • 在FORTRAN语言中,数组就是按列优先顺序存储的。 • 推广到多维数组的情况: • 行优先顺序:先排最右下标,从右到左,最后排最左下标 • 列优先顺序:先排最左下标,从左向右,最后排最右下标。

  9. 计算机如何实现数组元素的随机存取? 如何计算数组元素的地址? 按上述两种方式顺序存储的序组,只要知道: • 开始结点的存放地址(即基地址), • 维数 • 每维的上、下界 • 每个数组元素所占用的单元数, 就可以将数组元素的存放地址表示为其下标的线性函数。因此,数组中的任一元素可以在相同的时间内存取,即顺序存储的数组是一个随机存取结构。

  10. 如何计算数组元素的地址? a a a a a a …… …… 00 00 01 01 0n 0n - - 1 1 a a a a a a …… …… 10 10 11 11 1n 1n - - 1 1 …………………………. …………………………. a a a a a a m m - - 1 0 1 0 m m - - 1 1 …… 1 1 …… m m - - 1 n 1 n - - 1 1 内存 内存 • 一维数组 • 二维数组 • 三维数组 0 ListSize -1

  11. 假设数组各维的下界是1,按“行优先顺序”存储,假设每个元素占用d个存储单元。假设数组各维的下界是1,按“行优先顺序”存储,假设每个元素占用d个存储单元。 • 二维数组Amn, aij的地址计算函数为: LOC(aij)=LOC(a11)+[(i-1)*n+j-1]*d • 三维数组Amnp,aijk的地址计算函数为: LOC(aijk)=LOC(a111)+[(i-1)*n*p+(j-1)*p +(k-1)]*d

  12. 更一般的二维数组是A[c1..d1,c2..d2],这里c1,c2不一定是1。更一般的二维数组是A[c1..d1,c2..d2],这里c1,c2不一定是1。 aij的地址计算函数为: LOC(aij)=LOC(ac1c2)+[(i-c1)*(d2-c2+1)+j-c2)]*d • 例如,在C语言中,数组各维下标的下界是0,因此在C语言中,二维数组的地址计算公式为: LOC(aij)=LOC(a00)+(i*(d2+1)+j)*d

  13. 最基本的原理 Ai1…in的起始地址 第一个元素的起始地址 该元素前面的元素个数 单位长度 = 〸 ╳

  14. 程序员试题

  15. 2006-1 • 对于二维数组a[0…4,1…5],设每个元素占1个存储单元,且以行为主序存储,则元素a[2,1]相对于数组空间起始地址的偏移量是___(40)___。(40)A.5B.10 C.15D.25 2003 • 设数组a[3..16,5..20]的元素以列为主序存放,每个元素占用两个存储单元,则数组元素a[i,j](3≤i≤16,5≤j≤20)的地址计算公式为___(11)___。 (11)A.a-118+2i+28j B.a-116+2i+28j C.a-144+2i+28j D.a-146+2i+28j

  16. 2001 • 二维数组X 的行下标范围是0~5,列下标范围是1~8,每个数组元素占六个字节,则该数组的体积为__(6)__个字节,若已知X 的最后一个元素的起始字节地址为382,则X 的首地址(即第一个元素的起始字节地址)为__(7)__,记为Xd。若按行存储,则X{1,5] 的起始地址是__(8)__, 结束字节地址是__(9)__。若按列存储,则X[4,8]的起始字节地址为__(10)__。 • (6): A.210 B.240 C.288 D.294 • (7): A.0 B.6 C.94 D.100 • (8): A.Xd+24 B.Xd+72 C.Xd+78 D.Xd+144 • (9): A.Xd+29 B.Xd+77 C.Xd+83 D.Xd+147 • (10):A.Xd+186 B.Xd+234 C.Xd+270 D.Xd+276

  17. 5.2 矩阵的压缩存储

  18. 在编程时,简单而又自然的方法,是将矩阵描述为一个二维数组。矩阵在这种存储表示之下,可以对其元素进行随机存取。在编程时,简单而又自然的方法,是将矩阵描述为一个二维数组。矩阵在这种存储表示之下,可以对其元素进行随机存取。 • 但是在一些特殊矩阵中,非零元素呈某种规律分布或者矩阵中有大量的零元素,如果仍用二维数组存,会造成极大的浪费,尤其是处理高阶矩阵的时候。 • 为了节省存储空间, 我们可以对这类矩阵进行压缩存储。

  19. 5.2.1 几种常见的特殊矩阵 对称矩阵 在一个n阶方阵A中,若元素满足下述性质:aij=aji 0≦i,j≦n-1,则称A为对称矩阵。 特征:元素关于主对角线对称 压缩存储的办法: 只存矩阵中上三角或下三角中的元素。 所需空间:

  20. 三角矩阵 • 特征: • 上三角矩阵中,主对角线的下三角中的元素均为常数。在大多数情况下,常数为零。 • 下三角矩阵正好相反。 • 压缩方法: • 只存上(下)三角阵中上(下)三角中的元素 • 常数c可共享一个存储空间 • 所需空间:

  21. 对角矩阵 • 特征: • 所有的非零元素集中在以主对角线为中心的带状区域中, • 即除了主对角线和主对角线相邻两侧的若干条对角线上的元素之外,其余元素皆为零。 • 压缩存储的办法: 只存对角线上的元素。 • 存三对角矩阵所需的空间: 三对角矩阵

  22. 稀疏矩阵 • 特征:只有少量非零元素,且非零元素的分布没有规律。 • 压缩存储的办法: 只存非零元素。 • 所需空间:与非零元素的个数和存储方式有关。

  23. 5.2.2 特殊矩阵的压缩存储 • 矩阵类型 • 对称矩阵 • 三角矩阵 • 对角矩阵 • 压缩的基本思想: • 只存有用的元素 • 由用二维数组改为用一维数组来存放 • 说明: • 按C语言中规定,下标从0开始 • 不失一般性,按“行优先顺序”存储

  24. = 所需空间 • 关键问题 • 如何确定一维数组的大小? • 如何确定矩阵元素在一维数组中的位置?从而保证对矩阵元素的随机存取 Aij的位置 = 该元素前的元素个数

  25. 1. 对称矩阵 • 如何确定一维数组的大小? • 设:存放下三角阵中的元素, • 则:如何确定元素Aij在一维数组中的位置?

  26. 2. 三角矩阵 • 如何确定一维数组的大小? • 设:在下三角阵中, • 则:如何确定元素Aij在一维数组中的位置?

  27. 3.三对角矩阵 • 如何确定一维数组的大小? • 如何确定元素Aij在一维数组中的位置? 在Aij之前有i行,共有3*i-1个非零元素, 在第i行, aij之前有j-i+1个非零元素, 3*i-1+(j-i+1) = 2*i+j

  28. 程序员试题 2004-1 对矩阵压缩存储的主要目的是__(5)__。 (5) A.方便运算 B.节省存储空间 C.降低计算复杂度 D.提高运算速度 2003 将一个三对角矩阵A[l..100,1..100]中的元素按行存储在一维数组B[l..298]中,矩阵A中的元素A[66,65]在数组B中的下标为___(4)___。 (4) A.195 B.196 C.197 D.198

  29. 5.2.3 稀疏矩阵的压缩存储 • 顺序存储:三元组表 • 链式存储:十字链表

  30. 1.三元组表存稀疏矩阵 • 考虑: • 只存非零元素 • 一个非零元素的必需信息有:(i,j,aij) • 记录一个稀疏矩阵的必需信息有:行数M,列数N,非零元素个数T M=5 N=5 T=7

  31. 三元组表的C语言描述 #define maxsize 10000 typedef int datatype; typedef struct{/*三元组结点*/ int i,j; datatype v; }TriTupleNode; typedef struct{ TriTupleNode data[maxsize]; /*三元组表*/ int m,n,t;/*稀疏矩阵的行数,列数,非零元素个数*/ }TriTupleTable;

  32. 2.带行指针的三元组表 • 把具有相同行号的非零元用一个单链表连接起来,稀疏矩阵中的若干行组成若干个单链表,合起来称为带行指针的链表。

  33. 3.十字链表

  34. 5.2.4应用举例:稀疏矩阵的转置 1.矩阵转置的数学解释 一个m×n的矩阵A,它的转置B是一个n×m的矩阵,且a[i][j]=b[j][i],0≦i≦m,0≦j≦n。 Aij=Bji

  35. 2.利用三元组表实现转置 Aij=Bji M=4 N=2 T=5 M=2 N=4 T=5

  36. 思想一:直接交换a.data中i和j的内容 问题:b.data是一个按列优先顺序存储的稀疏矩阵B 解决方法:重新排列B中三元组的顺序。 Aij=Bji M=2 N=4 T=5 按i排序 M=4 N=2 T=5

  37. M=2 N=4 T=5 b.m=a.n; b.n=a.m; b.t=a.t;/*基本信息的赋值*/ /*按交换i、j的方式给B的三元组赋值*/ for ( i=0; i<b.t; i++ ) { b.data[i].i=a.data[i].j; b.data[i].j=a.data[i].i; b.data[i].v=a.data[i].v;} /*扫描B,按i排序*/ M=4 N=2 T=5 按i排序

  38. 思想二:在A中按列序找三元组,写入B • B的行优先即A的列优先 • 对A的第col列 ,扫描三元组表a.data,找出所有列号等于col的三元组,将它们的行号和列号互换后依次放入b.data中,即可得到B的按行优先的压缩存储表示。 Aij=Bji col=0,没有匹配的三元组 col=1,找到2,3,4 col=2,找到5,6 M=4 N=2 T=5 M=2 N=4 T=5

  39. Void transmatrix(tripletable a,tripletable b) { int pa, pb, col; b.m=a.n; b.n=a.m; b.t=a.t; /*基本信息的赋值*/ if(b.t<=0) { printf(“A=0\n”); return 0;} /*无非零元素*/ pb=0; /*pb指向三元组表B中的当前位置*/ for(col=0;col<a.n;col++)/*按列col扫描表A*/ for(pa=0;pa<=a.t;pa++) /*pb指向表A中的当前位置*/ /*找所有列号等于col的三元组,i,j互换写放入B*/ if(a.data[pa].j==col){ b.data[pb].i=a.data[pa].j; b.data[pb].j=a.data[pa].i; b.data[pb].v=a.data[pa].v; pb++; } }

  40. 算法分析 • 主要的工作是在pa和col的两个循环中完成的,故算法的时间复杂度为O(n*t),即矩阵的列数和非零元的个数的乘积成正比。 • 传统矩阵的转置算法的时间复杂度为O(n*m) • 当非零元素的个数t和m*n同数量级时,该算法的时间复杂度为O(m*n2)。(最坏情况) • 三元组顺序表虽然节省了存储空间,但时间复杂度比一般矩阵转置的算法还要复杂,同时还有可能增加算法的难度。因此,此算法仅适用于t<=m*n的情况。

  41. 思想三:快速转置 • 基本思想:在A中按行序找三元组,确定该三元组在B中的位置,写入B. • 关键问题:如何确定每个三元组在B中的位置 • A中三元组在B的中位置= 每列的第一个非零元素在数组B中应有的位置 + 每一列非零元素的个数

  42. M=2 N=4 T=5 M=4 N=2 T=5 Aij=Bji 由递推关系得出cpos的值: cpos[0]=0 cpos[i]=cpos[i-1]+cnum[i-1]

  43. void fasttranstri(tritupletable b,tritupletable a) { intcol;/*当前列号*/ int pa, pb; /*pa,pb:三元组a,b的下标*/ int cnum[0..a.n], cpos[0..a.n]; b基本信息m,n,t的赋值; 若a无非零元素,则返回; 初始化数组cnum; /*统计a中每列非零元素的个数;*/ for(pa=0; pa<a.t; pa++) { col=a.data[pa].j; cnum[col]++;} /*由递推关系计算cpos的值*/ cpos[0]=0; for(col=1;col<=a.n;col++) cpos[col] = cpos[col-1] + cnum[col-1];

  44. /*扫描a,将元素交换i,j写入b*/ for( pa=0; pa<a.t; pa++ ){ col = a.data[p].j; pb = cpot[col]; b.data[pb].i = a.data[pa].j; b.data[pb].j = a.data[pa].i; b.data[pb].v = a.data[pa].v; cpos[col]++; } } }

  45. 算法分析 • 时间复杂度O(n+t)。 • 当非零元素的个数t和m*n同数量级时,该算法的时间复杂度为O(m*n),与不压缩存储的情况相同。

  46. 5.3 广义表

  47. 5.5.1 基本概念 广义表是第2章提到的线性表的推广。线性表中的元素仅限于原子项,即不可以再分,而广义表中的元素既可以是原子项,也可以是子表(另一个线性表)。 1.广义表的定义 广义表是n≥0个元素a1,a2,…,an的有限序列,其中每一个ai或者是原子,或者是一个子表。广义表通常记为LS=(a1,a2,…,an),其中LS为广义表的名字,n为广义表的长度, 每一个ai为广义表的元素。但在习惯中,一般用大写字母表示广义表,小写字母表示原子。 2.广义表举例 (1)A=( ),A为空表,长度为0。 (2)B=(a,(b,c)),B是长度为2的广义表,第一项为原子,第二项为子表。 (3)C=(x,y,z),C是长度为3的广义表,每一项都是原子。 (4)D=(B,C),D是长度为2的广义表,每一项都是上面提到的子表。 (5)E=(a,E),是长度为2的广义表,第一项为原子,第二项为它本身。

  48. 3.广义表的表示方法 1)用LS=(a1,a2,…,an)形式,其中每一个ai为原子或广义表 例如:A=(b,c), B=(a,A) , E=(a,E) 都是广义表。 2)将广义表中所有子表写到原子形式,并利用圆括号嵌套 例如,上面提到的广义表A、B、C可以描述为: A(b,c) B(a,A(b,c)) E(a,E(a,E(…))) 3)将广义表用树和图来描述

  49. 4.广义表的深度 一个广义表的深度是指该广义表展开后所含括号的层数。 . (1)A=(b,c) (2)B=(a,A) (3)C=(A,B) (4) E=(a,E) depth=1 depth=2 depth=3 depth=∞ E a 5.广义表的分类 (1)线性表:元素全部是原子的广义表。 (2)纯表:与树对应的广义表,见图 (1)和(2)。 (3)再入表:与图对应的广义表(允许结点共享),见图 (3)。 (4)递归表:允许有递归关系的广义表,例如(4)。 这四种表的关系满足: 递归表再入表纯表 线性表

More Related