1、第四章 多维数组与广义表,北京邮电大学 信息与通信工程学院,数据结构与STL,数据结构与STL,2,第四章 多维数组和广义表,学习内容:4.1 多维数组4.2 矩阵的压缩存储4.3 广义表 4.4 实例分析4.5 使用STL操作多维数组,数据结构与STL,3,4.1 多维数组,由类型相同的数据元素构成的有序集合。对于k维数组,每个元素都要受k个线性关系的约束。,数组一般不执行删除和插入操作,所以常采用顺序存储方法来存储数组,多维数组通常有两种存储方式:行优先存储和列优先存储。,数据结构与STL,4,行优先存储基本思想是按行存储,即存完第i行再接着存储第i+1行。按行优先顺序存储二维数组Amn,
2、线性序列为:a11,a12,a1n,a21,a22,a2n,am1,am2,amn,Loc(aij) =Loc(a11)+(i-1)n+j-1)c,在C+、PASCAL等语言中,数组都是按行优先存储的,数据结构与STL,5,列优先存储基本思想是按列存储,即存完第i列再接着存储第i+1列。例如存储二维数组Amn,按列优先顺序存储的线性序列为: a11,a21,am1,a12,a22,am2,a1n,a2n,amn,Loc(aij)=Loc(a11)+ (i-1+m(j-1)c,在FORTRAN语言中,数组是按列优先存储的,数据结构与STL,6,多维数组的存储,C+中设三维数组Amnp,第一个元素
3、为a000,若按行优先存储,则aijk前面共有inp+jp+k个元素;若按列优先存储,则aijk前面共有i+mj+mnk个元素,试分析四维数组或更高维数组的行优先存储和列优先存储。,数据结构与STL,7,第四章 多维数组和广义表,学习内容:4.1 多维数组4.2 矩阵的压缩存储4.3 广义表 4.4 实例分析4.5 使用STL操作多维数组,数据结构与STL,8,4.2 矩阵的压缩存储,矩阵是一种常见的处理对象 矩阵可看作是二维数组 对于一些数据元素具有特殊规律的矩阵,常常采用一些特殊的存储方法以减少存储空间,数据结构与STL,9,对称矩阵,共需要存储的元素数目,设所有元素存储到一维数组sa中,
4、aij存储在sak元素中,k与ij的关系?,k = i(i-1)/2+j (ij),若aij位于矩阵的上三角,如何存储?,数据结构与STL,10,思考:设n阶对称矩阵按行优先方式存储下三角元素,元素a00存储在sa0元素中,元素aij存储在sa100元素中,则下标i、j的值为多少?,数据结构与STL,11,三角矩阵,三角矩阵分为上三角矩阵和下三角矩阵。设n阶方阵A,若其下三角的元素除对角线外均为常数c,即aij=c,0jin,则称该方阵为上三角矩阵,对于n阶三角矩阵,需要存储n(n+1)/2+1个元素,数据结构与STL,12,按行优先存储n阶上三角矩阵,设aij存储到sak中,若aij位于矩阵
5、上三角,有0ijn,则在存储aij之前,sa数组中首先要存储前i行上三角的元素,然后再存储aij所在行从aii到ai,j-1的元素,若aij位于矩阵下三角,有0jin,此时所有的aij具有相同的值,只需保存1个值,k = n(n+1)/2 (0jin),数据结构与STL,13,思考,按行优先存储n阶下三角矩阵时,首先存储下三角的元素,最后存储上三角的常数项c。给出aij与sak的对应关系。,对于按列优先方式存储的n阶三角矩阵,请推导元素存储位置k与下标i、j的对应关系,数据结构与STL,14,对角矩阵,所有非零元素都集中在对角线附近的方阵,三对角矩阵,在存储对角矩阵时,可将对角线附近的带状区域
6、元素立起来,形成一个列数较少的新矩阵,然后可按行优先方式存储这个新矩阵。,数据结构与STL,15,n维m对角矩阵A(m为奇数),设其对角线附近的元素aij存储到一维数组元素sak中。由于aij在对角线附近,因此有: max(i-(m-1)/2,0)jmin(i+(m-1)/2,n-1) aij之前共有i行,每行m个元素,因此首先要存储这mi个元素。在aij所在行上,aij之前共有j-i+(m-1)/2个元素。因此在存储aij之前,总共要存储mi+j-i+(m-1)/2个元素,即有: k=mi+j-i+(m-1)/2=(m-1)i+j+(m-1)/2,数据结构与STL,16,4.2.2 稀疏矩阵
7、压缩存储,矩阵Amn中的非零元素个数s远远小于矩阵元素的总数mn,存储稀疏矩阵时,只需要存储非零元素。常见的稀疏矩阵压缩方法:三元组表和十字链表,稀疏矩阵中每个非零元素的行号、列号及值构成一个三元组(3-tuples),数据结构与STL,17,#define MAX_ELEMENT_NUMBER 1000 template struct MatrixNode /定义三元组结构 int row; /非零元素的行号int col; /非零元素的列号T value; /非零元素的值 ; template struct SpareMatrix /定义三元组表结构 int m; /稀疏矩阵的行数int
8、n; /稀疏矩阵的列数int t; /稀疏矩阵非零元素的个数MatrixNode dataMAX_ELEMENT_NUMBER;/存储非零元素对应的三元组 ;,数据结构与STL,18,稀疏矩阵的转置操作,转置,数据结构与STL,19,稀疏矩阵简单转置算法,遍历n趟三元组表:第一趟遍历找出列号为0的三元组,并将其行号和列号对调,添加到转置矩阵对应的三元组表中。第二趟遍历找出列号为1的三元组并进行相同的操作,依次类推,最后一趟遍历找出列号为n-1的三元组。 由于每趟遍历都需要比较所有的t个三元组的列号,因此算法的时间复杂度为O(nt)。,数据结构与STL,20,简单转置算法,/将稀疏矩阵OrigM
9、at转置为TransMat template void TransMat(SpareMatrix * OrigMat, SpareMatrix * TransMat) TransMat-m = OrigMat-n;/设置转置矩阵的行数TransMat-n = OrigMat-m;/设置转置矩阵的列数TransMat-t = 0;/初始时转置矩阵的非零元素个数为for (int col=0;coln;col+)for (int j=0;jt;j+)if (OrigMat-dataj.col = col)/找出列号为col的三元组TransMat-dataTransMat-t.col = Orig
10、Mat-dataj.row ;TransMat-dataTransMat-t.row = OrigMat-dataj.col ;TransMat-dataTransMat-t.value = OrigMat-dataj.value ;TransMat-t+;/非零元素个数增 ,数据结构与STL,21,快速的稀疏矩阵转置算法,时间复杂度为O(n+t),在原始三元组表(设为A)依次取每个三元组,交换其行号和列号后,直接存放到转置矩阵的三元组表(设为B)中的适当位置。关键的问题:如何确定三元组在B中的位置A中第0列的第一个非零元素一定存储在B中下标为0的位置上,该列中其它非零元素应存放在B0后面连续
11、的位置上。 第1列的第一个非零元素在B中的位置便等于第0列的第一个非零元素在B中的位置加上第0列的非零元素的个数。,数据结构与STL,22,引入两个数组作为辅助数据结构: numbern:存储矩阵A中每列非零元素的个数; positionn:初始值表示矩阵A中每列的第一个非零元素在B中的位置,数据结构与STL,23,number,position,2,1,1,2,0,1,2,3,4,6,6,0,1,0 1 2 3 4 5,5,7,3,4,6,2,数据结构与STL,24,算法的伪代码,1. 设置转置矩阵B的行数、列数和非零元素的个数; 2. 计算A中每一列的非零元素个数,存储到number数组;
12、 3. 计算A中每一列的第一个非零元素在B中的下标,存储到position数组; 4. 依次取A中的每一个非零元素对应的三元组;4.1 确定该元素在B中的下标pb;4.2 将该元素的行号列号交换后存入B中pb的位置;4.3 预置该元素所在列的下一个元素的存放位置;,数据结构与STL,25,十字链表,每个非零元素,采用一个五元组结点表示,template struct snode /十字链表五元组结点 int row,col;/行号与列号T val; /值struct snode * cnext, rnext;/列指针与行指针 ;,同一行的非零元素构成一个带头结点的循环链表,同一列的非零元素也构
13、成一个带头结点的循环链表。,数据结构与STL,26,数据结构与STL,27,第四章 多维数组和广义表,学习内容:4.1 多维数组4.2 矩阵的压缩存储4.3 广义表 4.4 实例分析4.5 使用STL操作多维数组,数据结构与STL,28,4.3.1 广义表的逻辑结构,广义表(lists)也是n(n0)个元素a1,a2,an构成的有限序列,与线性表不同的是,ai可以是原子结点,也可以是一个广义表,因此广义表是递归定义的。,二维数组就是一种广义表,每行是一个结点,每个结点实际上又是由一行元素构成。,数据结构与STL,29,广义表记作LS=(a1,a2,an),LS是广义表的名称,n为广义表的长度,
14、A =(a,b,c) 长度为3的广义表 B=(A,d) 长度为2的广义表 C=(A,B) 长度为2的广义表 D=() 长度为0的空广义表 E=() 长度为1的广义表 F=(e,F) 长度为2的广义表,为了书写方便,在定义广义表时也可以把等号去掉,如 A(a,b,c),B(A(a,b,c),d),数据结构与STL,30,广义表的表示,广义表:A B C D E F,A(a,b,c) B(A,d) C(A,B) D() E() F(e,F),数据结构与STL,31,广义表的两个基本操作:取表头GetHead(LS)取表尾GetTail(LS) 对于长度为n(n1)的广义表LS=(a1,a2,an)
15、,称a1为广义表LS的表头,子表(a2,an)为广义表LS的表尾,GetHead(A(a,b,c)=aGetTail(A(a,b,c)=(b,c)GetHead(E()=()GetTail(E()=(),数据结构与STL,32,4.3.2 广义表的存储结构,将链式存储方法存储的广义表称为广义链表,在不同的应用中,广义链表的具体存储结构也不尽相同 一种比较基本的存储方法广义单链表,假定表中的所有原子结点类型相同。,数据结构与STL,33,广义单链表举例,数据结构与STL,34,第四章 多维数组和广义表,学习内容:4.1 多维数组4.2 矩阵的压缩存储4.3 广义表 4.4 实例分析4.5 使用S
16、TL操作多维数组,数据结构与STL,35,4.4.1 BMP文件结构分析,数字图像在计算机中往往按矩阵的形式被存储和操作。最常见的图像格式:位图文件,单色图像:图像中每个像素只需要一个bit存储 灰度图象:一般有256级灰度 伪彩色图像:类似于灰度图象,每个像素值由一个字节组成,因此共有256中颜色 24位真彩色图像:图象中每个像素值由三个字节表示,三个字节分别代表红、绿、蓝三个分量,取值为0255。不需要图像颜色表。,通常将256级灰度和伪彩色图像称为8位位图图像,数据结构与STL,36,lenna图像,该图像混和了许多的细致部分、平滑区、阴影、 纹理等,非常适合测试各类图像处理算法,是个相
17、当好的测试图像。,数据结构与STL,37,基本的BMP文件结构,typedef struct tagBITMAPFILEHEADER /位图文件的类型,0X4D42WORD bfType; /位图文件的大小,以字节为单位DWORD bfSize;/保留字,必须为0 WORD bfReserved1; /保留字,必须为0WORD bfReserved2; /位图数据的起始位置DWORD bfOffBits; BITMAPFILEHEADER;,数据结构与STL,38,位图信息头结构用于说明位图的宽度、高度、颜色深度等信息。该结构定义如下: typedef struct tagBITMAPINFO
18、HEADERDWORD biSize; /本结构所占用的字节数LONG biWidth; /位图的宽度LONG biHeight; /位图的高度WORD biPlanes; /目标设备的级别,必须为1WORD biBitCount; /每个像素所需的位数,一般为1(双色),4(16色),8(256色)或24(真彩色)等DWORD biCompression; /压缩类型,一般为0(不压缩),1(BI_RLE8压缩),2(BI_RLE4压缩)DWORD biSizeImage; /位图的大小,以字节为单位LONG biXPelsPerMeter;/位图水平分辨率(每米像素数)LONG biYPe
19、lsPerMeter;/位图垂直分辨率(每米像素数)DWORD biClrUsed; /位图实际使用的颜色表中的颜色数DWORD biClrImportant; /位图显示过程中重要的颜色数 BITMAPINFOHEADER;,数据结构与STL,39,typedef struct tagRGBQUAD BYTE rgbBlue; /蓝色的亮度(范围0255)BYTE rgbGreen; /绿色的亮度(范围0255)BYTE rgbRed; /红色的亮度(范围0255)BYTE rgbReserved; /保留字,必须为0 RGBQUAD;,biBitCount=1:单色图像,8个像素占用1个字
20、节,位图颜色表只需要包含2个表项 biBitCount=4:16色图像,2个像素占用1个字节,位图颜色表包含16个表项 biBitCount=8:256色图像,1个像素占用1个字节,位图颜色表包含256个表项 biBitCount=24真彩色图像,1个像素占用3个字节,位图颜色表不包含表项,数据结构与STL,40,位图数据存储方法: 按各行自下而上、每行自左到右记录了其每一个像素值,因此图像存储时是上下颠倒的 图像数据以行为单位进行存储,每行像素存储所占的字节数必须为4的倍数,不足时将多余位用“0”填充,数据结构与STL,41,操作BMP文件的简单类CDib,class CDib public
21、: CDib(); /默认构造函数CDib(); /析构函数bool Load( const char * filename);/打开BMP文件bool Save( const char * filename);/保存BMP文件bool Create(int nWidth, int nHeight, int nColor);/建立默认BMP结构void Circle(); /以图像中心为圆心画圆 private: void SetPixelColor(int i,int j); /画圆时设置像素点(i,j)的颜色int GetNumberOfColors(); /获取颜色表的表项数目void
22、SetColor(RGBQUAD * rgb,BYTE r,BYTE g, BYTE b); / 设置颜色表项BITMAPFILEHEADER m_BitmapFileHeader; /BMP文件头结构BITMAPINFOHEADER * m_pBitmapInfoHeader; /指向BMP文件信息结构RGBQUAD * m_pRgbQuad; /指向颜色表BYTE * m_pData; /像素阵列BYTE * pDib; ;,数据结构与STL,42,4.4.2 简单图像处理平滑技术,人们拍摄或扫描的图像一般都因受到某种干扰而含有噪声 解决方法:平滑,经典的平滑技术对噪声图像使用局部算子,当
23、对某一个像素进行平滑处理时,仅对它的局部小邻域内的一些像素进行处理,其优点是计算效率高,而且可以对多个像素并行处理。,最简单图象平滑:邻域平均法,数据结构与STL,43,4-邻域平均 8-邻域平均,设灰度图像的宽度和高度分别为nWidth和nHeight,原始图像倒置存储在数组pData 中,数组长度为nWidthnHeight。数组中的每个元素对应一个像素,占1个字节。图像平滑后的数据存储到pNewData 数组中,数组大小与原数组相同。,数据结构与STL,44,数据结构与STL,45,第四章 多维数组和广义表,学习内容:4.1 多维数组4.2 矩阵的压缩存储4.3 广义表 4.4 实例分析
24、4.5 使用STL操作多维数组,数据结构与STL,46,4.5 使用STL操作多维数组,STL本身并没有二维、三维等多维数组的概念,但并不能说STL不支持多维数组,vector ivv; 对象ivv是向量的向量,相当于一个二维数组,但各维上元素的数目可以不同。 注意:“ ”非“”,如果希望向量各维上的元素数目都相同,可以基于vector单独设计一个二维数组的类来完成此功能。 见教材对C2DVector类的定义。,C2DVector my2DArray(3,4); /建立一个 34 的数组。 My2DArray.GrowCol(5); /动态增加到 5 列。 类中已经重载了操作符 ,因此它可以像常规 C/C+ 二维数组一样使用。 my2DArrayxy = 5;,数据结构与STL,47,本章小结,多维数组,广义表,实例分析,操作多维数组,逻辑结构,存储结构,存 储 寻 址,行优先存储,列优先存储,对称矩阵,三角矩阵,对角矩阵,逻辑结构,存储结构,稀疏矩阵,三元组表,STL,矩阵压缩,十字链表,广义链表,BMP文件操作,图像平滑,转 置 算 法,