1 / 36

第四章 数组与特殊矩阵 第一节 数组 第二节 特殊矩阵的压缩存储 第三节 稀疏矩阵 本 章 小 结 实 训 思 考 与 习 题

第四章 数组与特殊矩阵 第一节 数组 第二节 特殊矩阵的压缩存储 第三节 稀疏矩阵 本 章 小 结 实 训 思 考 与 习 题. 第四章 数组与特殊矩阵. 学习要求: 数组是一种比较常见的数据结构,本章的目标是让读者了解数组的特性、数组的表示方法,掌握数组的逻辑结构及内存的存储结构,熟悉几种特殊矩阵的压缩存储方法。 主要内容: 本章主要讨论数组的基本概念和逻辑结构、存储方式以及几种特殊矩阵的压缩存储方法。. 第一节 数组.

asta
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. 第四章 数组与特殊矩阵 第一节 数组 第二节 特殊矩阵的压缩存储 第三节 稀疏矩阵 本 章 小 结 实 训 思 考 与 习 题

  2. 第四章 数组与特殊矩阵 学习要求: 数组是一种比较常见的数据结构,本章的目标是让读者了解数组的特性、数组的表示方法,掌握数组的逻辑结构及内存的存储结构,熟悉几种特殊矩阵的压缩存储方法。 主要内容: 本章主要讨论数组的基本概念和逻辑结构、存储方式以及几种特殊矩阵的压缩存储方法。

  3. 第一节 数组 数组是人们很熟悉的数据类型,几乎所有的程序设计语言中都设有数组类型。我们把多维数组看成是广义的线性表,即看成是这样一个线性表:它的每一个数据元素都是一个定长线性表,或理解成多维数组对应的线性表中的数据元素本身又是一个线性表。本节重点讨论二维数组的逻辑结构及其内存映像,多维数组可以在二维数组的分析基础上加以推广。 一、数组的基本概念 高级语言中的数组在计算机内是用一批连续的内存单元来表示的,称为数组的顺序存储结构。在实际使用中还可以根据需要选择数组的其他存储方式。 数组是由下标(index)和值(value)组成的序对的集合。在数组中,一旦给定下标,都存在一个与其相对应的值,这个值就称为数组元素。 数组是一个固定格式和数量的数据有序集,每一个数据元素用唯一的一个或一组下标标识,在数组上不能做插入、删除数据元素的操作。数组

  4. 一旦被定义,它的维数和维界就不再改变。因此,数组的运算通常只有两种基本运算: 1.给定一组下标,存取相应的数据元素。 2.给定一组下标,修改相应的数据元素的值。 二、数组的逻辑结构 数组中的数据元素均属于同一数据类型。在二维数组中,每个元素都受行和列关系的约束。设定A是一个二维数组,如图4.1(a)所示,以m行n列的矩阵形式表示。 图4.1(a) m行n列的二维数组

  5. 图4.1(b) 行向量形式的二维数组 图4.1(c) 列向量形式的二维数组

  6. 它可以看成是一个一维数组,即可看成是一个线性表A=(a1,a2,…,an),其中,每一个元素ai对应一个列向量形式的线性表ai=(a1i,a2i,…,ami),如图4.1(c)所示。这样我们就可以把二维数组看成是由几个列向量组成的线性表了。同样,可以把二维数组A看成是一个线性表A=(a1, a2 ,…, am),其中,每一个元素aj对应一个行向量形式的线性表aj=(aj1,aj2,aj3,…,ajn),如图4.1(b)所示。 二维数组可以看作“数据元素是一维数组”的一维数组,三维数组可以看作“数据元素是二维数组”的一维数组,依此类推。

  7. 三、数组的内存映像 现在来讨论数组在计算机中的内存表示。通常,数组在内存被映像为向量,即向量作为数组的一种存储结构,数组是以顺序存储方式存放在计算机中的,而随机存取是顺序存储结构的主要特性。 对于一维数组,可根据数组元素的下标得到它的存储地址,按下标顺序分配即可。 对于二维数组,可用向量(顺序)存储结构来存放。用向量结构来存放二维数组中的元素,一定要按某种次序将元素排成一个线性序列,顺序存放的次序有两种规则: 1.先行后列顺序,或者称为行优先顺序,在PASCAL和C语言中,数组就是按行优先顺序存储的。 2.先列后行顺序,或者称为列优先顺序,在FORTRAN语言中,数组就是按列优先顺序存储的。 例如,B数组是个5行3列的二维数组,对应的两种规则的顺序存储结构如图4.2所示。

  8. 图4.2 B数组的两种顺序存放示意图 以上规则可以推广到多维数组:以行优先顺序的分配规律是:最右边的下标先变化,即最右边的下标从小到大,循环一遍后,右边的第2个下标再变化,……,从右向左,最后是左下标。以列优先顺序的分配规律恰好与之相反:最左边的下标先变化,即最左边的下标从小到大,循环一遍后,左边的第2个下标再变化,……,从左向右,最后是右下标。 对于顺序存储的数组,只要知道向量的起始地址,数组的行号数和列号数,以及每个数组元素所占用的存储单元个数,就可以求得给定下标的数组元素的存储起始地址。

  9. 例如,一个二维数组A(m×n)按行优先存储在向量中。设定数组中第一个元素的存储起始地址为LOC(a1,1),并已知某个数据元素的下标为i和j(1≤i≤m,1≤j≤n),及每个数据元素占用的存储单元数为b,就可以计算该数据元素的存储起始地址:例如,一个二维数组A(m×n)按行优先存储在向量中。设定数组中第一个元素的存储起始地址为LOC(a1,1),并已知某个数据元素的下标为i和j(1≤i≤m,1≤j≤n),及每个数据元素占用的存储单元数为b,就可以计算该数据元素的存储起始地址: LOC(ai,j)=LOC(a1,1)+[n*(i-1)+(j-1)]*b 值得一提的是:在C语言中,数组下标的下界是0,因此在C语言中,如果数组元素从0下标存放起,地址的计算公式是: LOC(ai,j)=LOC(a0,0)+(i*n+j)*b 若二维数组A(m×n)按列优先顺序存储在向量中,则相应A(i,j)的地址的计算公式为: LOC(ai,j)=LOC(a1,1)+[m*(j-1)+(i-1)]*b 或 LOC(ai,j)=LOC(a0,0)+(m*j+i)*b

  10. 第二节 特殊矩阵的压缩存储 在科学与工程计算问题中,矩阵是一种常用的数学对象,在用高级语言程序时,简单而又自然的方法,就是将一个矩阵描述为一个二维数组。矩阵在这种存储表示之下,可以对其元素进行随机存取,各种矩阵运算也非常简单。这样,利用上一节的地址计算公式可以快速访问矩阵中的每个元素。然而,实际应用中会遇到一些特殊矩阵,所谓特殊矩阵,是指矩阵中值相同的元素或者零元素的分布有一定的规律。例如,对称矩阵、三角矩阵和带状矩阵都是特殊矩阵。 为了节省存储空间,可以对这些矩阵进行压缩存储。所谓压缩存储就是为多个值相同的元素只分配给一个存储空间,对零元素不分配存储空间。由于特殊矩阵中非零元素的分布有明显的规律,因此我们可将其压缩存储到一个一维数组中,并找到每个非零元素在一维数组中的对应关系。 一、对称矩阵 (一) 对称矩阵 若一个n阶矩阵A中的元素满足下述性质: aij=aji (1≤i≤n,1≤j≤n)

  11. 则称A为n阶对称矩阵。例如A矩阵是一个5阶的对称矩阵,则称A为n阶对称矩阵。例如A矩阵是一个5阶的对称矩阵, 如图4.3所示。 (二)对称矩阵的压缩存储 对于对称矩阵,可以为每一对对称矩阵元素分配一个存储空间,则可以将n2个元素压缩存储到n(n+1)/2个空间中,节约了n(n-1)/2个存储单元。当n较大时,这是相当可观的一部分存储资源。 下面以行优先存储其下三角(包括对角线)中的元素。 在下三角矩阵中共有n(n+1)/2个元素,可开辟一个长度为n(n+1)/2的一维数组B,然后一行接一行地依次存放对称矩阵中下三角(包括对角线)部分的元素。经压缩后,存放在一维数组B中的形式如图4.4所示。

  12. 图4.4 对称矩阵的压缩存储 显然,对称矩阵A用一维数组B表示后,可以按如下原则访问对称矩阵A中的第i行、第j行的元素aij。 1如果aij为下三角部分元素(j≤i),则它存放在一维数组B的第i(i-1)/2+j个元素中。 2如果aij为非下三角元素(j>i),则它可以对应一维数组B的第j(j-1)/2+i个元素的值。即有如下关系: aij=B[i(i-1)/2+j]当j≤i B[j(j-1)/2+i]当j>i

  13. 下三角矩阵A也可以用以列优先的方式压缩在一维数组B中,请读者自己练习。下三角矩阵A也可以用以列优先的方式压缩在一维数组B中,请读者自己练习。 若对图4.3的5阶对称矩阵进行以行优先压缩存储,其结果如图4.5所示。 图4.5对称矩阵A的压缩存储 二、三角矩阵 三角矩阵分为下三角矩阵和上三角矩阵。所谓下(上)三角矩阵是指矩阵的上(下)三角(不包括对角线)中的元素均为常数c或0的n阶矩阵。例如,B矩阵是一个下三角矩阵;C矩阵是一个上三角矩阵,如图4.6所示。 下面分别下面讨论它们的压缩存储方法。

  14. 图4.6 三角矩阵 (一)下三角矩阵 下三角矩阵的压缩存储与对称矩阵类似,不同之处在于存完下三角矩阵中的元素之后,紧接着要存储对角线上方的常量c,因为是同一个常数,所以再加上一个常数c的存储空间即可,这样一共就存储了n(n+1)/2+1个元素。 在实际应用中,下三角矩阵一般应采用以行优先压缩存储的方法,因为在以列优先存储下三角矩阵,访问下三角矩阵中的元素时,其下标运算要比以行优先压缩存储复杂一些。 (二)上三角矩阵 对于上三角矩阵,压缩存储的思想与下三角矩阵类似,但采用以列优先存储比较方便,其存储形式如图4.7所示。

  15. 图4.7上三角矩阵的压缩存储 在以列优先压缩存储上三角矩阵的情况下,访问上三角矩阵中第i行、第j行元素aij的公式为:

  16. 三、带状矩阵 一个n阶方阵,如果它的全部非零元素落在一个以对角线为中心的带状区域中,则称该矩阵为带状矩阵。若有一n阶矩阵A为带状矩阵,如果存在最小正数m ,满足当∣i-j∣≥m 时,aij =0,这时称w=2m-1为矩阵A的带宽。如图4.8(a)是一个w=3(m=2)的带状矩阵。带状矩阵也称为对角矩阵。由图4.8(a)可看出,在这种矩阵中,所有非零元素都集中在以主对角线为中心的带状区域中,即除了主对角线和它的上下方若干条对角线的元素外,所有其他元素都为零(或同一个常数c)。 带状矩阵A也可以采用压缩存储。一种压缩方法是将A压缩到一个n行w列的二维数组B中,如图4.8(b)所示,当某行非零元素的个数小于带宽w时,先存放非零元素后补零。那么aij可映射为b i′j′,映射关系为:

  17. 另一种压缩方法是将带状矩阵压缩到一维数组C中去,按以行优先的顺序存储其非零元素,如图4.8(c)所示,按其压缩规律找到相应的访问公式。另一种压缩方法是将带状矩阵压缩到一维数组C中去,按以行优先的顺序存储其非零元素,如图4.8(c)所示,按其压缩规律找到相应的访问公式。 如当w=3时,一维数组C以行优先存放带状矩阵A中的元素aij时,其访问公式为: 图4.8 带状矩阵及压缩存储

  18. 第三节 稀疏矩阵 什么是稀疏矩阵?如果矩阵中非零元素的个数远远小于矩阵元素的总数,这样的矩阵称为稀疏矩阵。 对于稀疏矩阵,只考虑非零元素的存储。但由于非零元素的分布没有规律,为了能找到相应的元素,仅存储非零元素的值是不够的,还要记下它所在的行和列。 下面讨论稀疏矩阵的两种压缩存储方法。 一、稀疏矩阵的三元组表存储 将矩阵中的非零元素所在行、列以及它的值构成一个三元组结构体(i,j,v)。这样一个三元组(i,j,v)便唯一地确定了矩阵中的一个非零元素,其中i和j分别表示非零元素的行号和列号,v表示非零元素的值。 将三元组按行优先,同一行中列号从小到大的规律排列,则可得到一个元素类型是三元组的线性表,称为三元组表。

  19. 三元组表是稀疏矩阵的一种顺序存储结构。稀疏矩阵的三元组存储的数据类型描述如下:三元组表是稀疏矩阵的一种顺序存储结构。稀疏矩阵的三元组存储的数据类型描述如下: #define MAXSIZE 10000 typedef int datatype; typedef struct{ int i,j; /*非零元素的行、列*/ datatype v; /*非零元素值*/ } triple; /*三元组类型*/ typedef struct{ triple data[MAXSIZE]; /*三元组表*/ int m,n,t; /*矩阵的行、列及非零元素的个数*/ } tripletable;

  20. 这种表示方法,在矩阵很稀疏的情况下,对存储空间的需求量比一般存储少得多。例如,在图4.9所示的M矩阵中,它有6行、7列。如果每个元素占2个字节,按一般顺序存储则需要6×7×2=84个字节,而按三元组顺序存储,假设存放非零元素的行号和列号也各占2个字节,因有非零元素8个,则仅需8×3×2=48个字节。设定a是类型定义为tripletable的变量,表示稀疏矩阵M,图4.10是稀疏矩阵M所对应的三元组存储结构示意图。 图4.9 稀疏矩阵M

  21. 三元组存储结构因以行优先存放,存在以下的规律:元组中的第一列按行号的顺序由小到大排列,元组中的第二列是列号,列号在行号相同时也是由小到大排列。三元组存储结构因以行优先存放,存在以下的规律:元组中的第一列按行号的顺序由小到大排列,元组中的第二列是列号,列号在行号相同时也是由小到大排列。 图4.10 稀疏矩阵M的三元组结构a

  22. 二、稀疏矩阵的十字链表存储 三元组表可以看作是稀疏矩阵的顺序存储,这种表示方式适合求解稀疏矩阵的转置、相乘等运算。但当矩阵的非零元素的个数和位置在操作过程中变化较大时,如做一些操作(如加法、乘法)时,这种表示就十分不便了。为此,稀疏矩阵考虑采用链式存储结构来表示。 同以前链表表示相同,矩阵中的每个非零元素也用一个结点来表示,结点中除了表示非零元素的行、列、值(row,col,val)三个域外,还增加了两个指针域:向下域down用于链接同一列中的下一个非零元素;向右域right用于链接同一行中的下一个非零元素。其结点结构如图4.11(a)所示。 图4.11 十字链表的结点结构

  23. 这样一来,同一行的非零元素通过向右域right链接成一个线性链表,称为行链表;同一列的非零元素通过向下域down也链接成一个线性链表,称为列链表。矩阵中的每个非零元素既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,这种存储结构称为十字链表。这样一来,同一行的非零元素通过向右域right链接成一个线性链表,称为行链表;同一列的非零元素通过向下域down也链接成一个线性链表,称为列链表。矩阵中的每个非零元素既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,这种存储结构称为十字链表。 为了运算上的方便,给十字链表增加了一个表头结点,其结构与普通的存储非零元素的表头结点相同,如图4.11(b)所示。在实际应用中,可将表头结点的行、列域都设为零。由于行、列链表的表头结点的行列域均为零,而且都指向各自链表的第一个非零元素结点,所以行、列链表的表头结点可以合用。另外,表头结点的值域val没有使用,可以将其改造成指针域next,用于存放指向下一个表头结点的指针,并通过该指针域将所有的表头结点也链接成一个链表,在这个均是表头结点的链表中,再附加一个表头结点,作为“总”的表头结点,其指针域next指向第一个表头结点,结构和表头结点一样,其中值域row和col分别表示矩阵的行数和列数,另外两个指针域闲置。

  24. 例如,稀疏矩阵A如图4.12所示。 图4.12 稀疏矩阵A 可以用如图4.13所示的十字链表表示。 用十字链表表示稀疏矩阵的结构特点如下:

  25. 图4.13稀疏矩阵A的十字链表

  26. (1) 稀疏矩阵的每一行与每一列均用带表头结点的循环链表表示; (2) 表头结点中的行域与列域的值均置为0(即row=0,col=0); (3) 行、列链表的表头结点合用,且这些表头结点通过值域(即val)相链接,并增加一个结点作为它们的表头结点H,其行、列域值分别存放稀疏矩阵的行数与列数。 由此可以看出,只要给出头指针H的值,便可以扫描到稀疏矩阵中的任意一个非零元素。 三、稀疏矩阵的转置运算 矩阵的转置运算就是按一定规律变换元素的位置,即把位于(i,j)的元素换到(j,i)位置上。对于一个m×n的矩阵M,它的转置矩阵是一个n×m的矩阵N,且Mi,j=Nj,i,

  27. 其中,1≤i≤n,1≤j≤m。矩阵转置就是把矩阵元素的行和其中,1≤i≤n,1≤j≤m。矩阵转置就是把矩阵元素的行和 列对换。例如,图4.14的稀疏矩阵M的转置矩阵为图4.15 所示的稀疏矩阵N。 图4.14稀疏矩阵M 图 4.15稀疏矩阵M的转置矩阵N

  28. 将稀疏矩阵M和M矩阵转置后得到的稀疏矩阵N分别用三元组表存储,其结构示意图如图4.16、图4.17所示。将稀疏矩阵M和M矩阵转置后得到的稀疏矩阵N分别用三元组表存储,其结构示意图如图4.16、图4.17所示。 图4.16 稀疏矩阵M的三元组表结构 图4.17 转置矩阵N的三元组表结构

  29. a.data和b.data都具有上述三元组存放的规律,这是矩阵转置算法实现的依据。 算法思路: (1)矩阵M的行、列转化成矩阵N的列、行; (2)在a.data中依次找第一列的、第二列的,直到最后一列,并将找到的每个三元组的行、列交换后,按行号从小到大的顺序存储到b.data中即可。 用C语言描述稀疏矩阵的转置算法如下: void transpose (SPMATRIX b, SPMATRIX a) { int p,q,col b.m=a.n; b.n=a.m; b.t=a.t; if (a.t0) { q=1;

  30. for (col=1;col<=a.n; col++) for (p=1; p<=a.t; p++) if (a.data[p].j==col) { b.data[q].j=a.data[p].i; b.data[q].i=a.data[p].j; b.data[q].v=a.data[p].v; q++; } } }

  31. 本章小结 本章主要介绍的内容如下: 多维数组在计算机中有两种存放方式:行优先和列优先。 三种特殊矩阵:对称矩阵、三角矩阵和带状矩阵。 对称矩阵关于主对角线对称。为了节省存储单元,可以进行压缩存储,对角线以上的元素和对角线以下的元素可以共用存储单元,故n×n的对称矩阵只需n*(n+1)/2个存储单元即可。 三角矩阵有上三角矩阵和下三角矩阵之分,进行压缩存储时,n×n的三角矩阵只需n*(n+1)/2+1个存储单元即可。 带状矩阵也称为对角矩阵。一种压缩存储方法是将其压缩到一个n行w列的二维数组B中,另一种压缩存储方法是将带状矩阵压缩到向量中去,按以行优先,顺序地存储其非零元素,按其压缩规律,找到相应的访问公式。 稀疏矩阵的非零元素排列无任何规律,进行压缩存储时,可以采用三元组表示法或十字链表表示法。

  32. 实 训 一、实训目的 1.掌握稀疏矩阵的表示方法及其运算的实现。 2.实现稀疏矩阵在三元组表、十字链表等表示下的各种运算。 二、实训内容 1.问题描述: 稀疏矩阵是指那些多数元素为零的矩阵。利用“稀疏”特点进行存储和计算可以大大节省存储空间,提高计算效率。实现一个能进行稀疏矩阵基本运算的运算器。 2.基本要求: 以三元组顺序表表示稀疏矩阵,实现矩阵转置的运算。稀疏矩阵的输入形式采用三元组表示,而运算结果的矩阵则以通常的阵列形式列出。

  33. 3.测试数据: 三、实训过程 1.算法分析: (1)首先应输入矩阵的行数和列数,并判别给出的两个矩阵的行、列数对于所要求作的运算是否相匹配。可设矩阵的行数和列数均不超过20。 (2)程序可以对三元组的输入顺序加以限制,例如,按行优先。 (3)在用三元组表示稀疏矩阵时,相加或相减所得结果矩阵应该另生成,乘积矩阵也可用二维数组存放。

  34. 2.算法提示: #define MAXSIZE 100 struct node { int i,j; /*定义三元组的行、列号*/ int v; /*三元组的值*/ }; struct sparmatrix { int rows,cols; / *稀疏矩阵的行、列数*/ int terms; /*稀疏矩阵的非零元个数*/ struct node data[MAXSIZE]; /*存放稀疏矩阵的三元组表*/ }; void transpose(struct sparmatrix a) /*调用转置算法*/ 四、实训总结 通过本实训的实际操作,使读者掌握如何定义稀疏矩阵的三元组存储结构,在此基础上实现稀疏矩阵的初始化、取稀疏矩阵元素等基本操作,并最终利用它们来解决实际问题。

  35. 思考与习题 一、填空题 1.一维数组的逻辑结构是( ),存储结构是( );对于二维数组或多维数组,可分为( )和( )两种不同的存储方式。 2.对于一个二维数组A[m][n],若按以行优先存储,则任一元素aij相对于a00的地址为( )。 3.三维数组A[c1..d1,c2..d2,c3..d3]共含有( )个元素。 4.数组A[1..10,-2..6,2..8]以行优先的顺序存储,设第一个元素的首地址是100,每个元素占3个存储单元的存储空间,则元素a507的存储地址为( )。 二、选择题 1.二维数组M的成员是4个字符(每个字符占一个存储单元)组成的字符串,行下标i的范围从0到8,列下标j的范围从0到5,则存放M至少需要()个字节。 A.90 B.360 C.216 D.540

  36. 2.二维数组M的元素是4个字符(每个字符占一个存储单元)组成的字符串,行下标i的范围从0到4,列下标j的范围从0到5,M按行存储时元素m35的起始地址与M按列存储时元素( )的起始地址相同。 A.m43 B.m34 C.m35 D.m44 3.稀疏矩阵一般的压缩存储方法有两种,即()。 A.二维数组和三维数组 B. 三元组表和散列 C.三元组表和十字链表 D. 散列和十字链表 三、应用题 1.有数组A[4][4],把1到16个整数分别按顺序放入a00…a03,a10…a13,a20…a23,a30…a33中,编写一个函数获取数据,并求出两条对角线元素的乘积。 2.试写一个算法,查找十字链表中某一个非零元素x。 3.给定矩阵S如下,写出它的三元组表和十字链表。

More Related