收藏 分享(赏)

用三元组表示稀疏矩阵的乘法.ppt

上传人:hwpkd79526 文档编号:4109381 上传时间:2018-12-10 格式:PPT 页数:27 大小:334.50KB
下载 相关 举报
用三元组表示稀疏矩阵的乘法.ppt_第1页
第1页 / 共27页
用三元组表示稀疏矩阵的乘法.ppt_第2页
第2页 / 共27页
用三元组表示稀疏矩阵的乘法.ppt_第3页
第3页 / 共27页
用三元组表示稀疏矩阵的乘法.ppt_第4页
第4页 / 共27页
用三元组表示稀疏矩阵的乘法.ppt_第5页
第5页 / 共27页
点击查看更多>>
资源描述

1、用三元组表实现稀疏矩阵的乘法运算,两个矩阵相乘也是矩阵的一种常用的运算。设矩阵M是m1n1矩阵,N是m2n2矩阵;若可以相乘,则必须满足矩阵M的列数n1与矩阵N的行数m2相等,才能得到结果矩阵Q=MN(一个m1n2的矩阵)。 数学中矩阵Q中的元素的计算方法如下:,其中: 1im1, 1jn2。,根据数学上矩阵相乘的原理, 我们可以得到矩阵相乘的经典算法: for(i=1; i=m1; i+) for(j=1; j=n2; j+)Qij=0; for(k=1; k=n1; k+) Qij=Qij+Mik*Nkj; ,图5.17 Q=MN,图5.17给出了一个矩阵相乘的例子。当矩阵M、N是稀疏矩阵

2、时,我们可以采用三元组表的表示形式来实现矩阵的相乘。,图5.18 矩阵M、N、Q的三元组表,经典算法中,不论Mik、Nkj是否为零, 都要进行一次乘法运算,而实际上,这是没有必要的。采用三元组表的方法来实现时,因为三元组只对矩阵的非零元素做存储所以可以采用固定三元组表a中的元素(i,k,Mik)(1im1,1kn1),在三元组表b中找所有行号为k的的对应元素(k,j, Nkj)(1km2,1jn2)进行相乘、 累加,从而得到Qij,即以三元组表a中的元素为基准, 依次求出其与三元组表b的有效乘积。 ,算法中附设两个向量num 、first ,其中numrow表示三元组表b中第row行非零元素个

3、数(1rowm2), firstrow表示三元组表b中第row行第一个非零元素所在的位置。显然,firstrow+1-1指向三元组表b中第row行最后一个非零元素的位置。,first1=1; firstrow=firstrow-1+numrow-1, 2rowm2+1。,这里,firstm2+1-1表示最后一行最后一个非零元素的存储位置。当三元组表a中第i行非零元素的列号等于三元组表b中非零元素的行号时,则元素相乘并将结果累加。,图5.19 Q=MN,图5.20 图5.19中矩阵N对应的向量numrow, firstrow,Row 1 2 3 4 (5) Numrow 2 1 1 1 Firs

4、trow 1 3 4 5 6,define MAXSIZE 1000 /*非零元素的个数最多为1000*/define MAXROW 1000 /*矩阵最大行数为1000*/ typedef struct int row, col; /*该非零元素的行下标和列下标*/ ElementType e; /*该非零元素的值*/Triple; typedef struct Triple dataMAXSIZE+1; /* 非零元素的三元组表,data0未用*/int firstMAXROW+1; /* 三元组表中各行第一个非零元素所在的 位置 */int m, n, len;/*矩阵的行数、 列数和非

5、零元素的个数*/ TriSparMatrix;,具体算法如下: 该算法的时间主要耗费在乘法运算及累加上,其时间复杂度为O(A.lenB.n)。当A.len 接近于A.mA.n时,该算法时间复杂度接近于经典算法的时间复杂度O(A.mA.nB.n)。,稀疏矩阵的链式存储结构: 十字链表与用二维数组存储稀疏矩阵比较,用三元组表表示的稀疏矩阵不仅节约了空间,而且使得矩阵某些运算的运算时间比经典算法还少。但是在进行矩阵加法、减法和乘法等运算时,有时矩阵中的非零元素的位置和个数会发生很大的变化。如A=A+B, 将矩阵B加到矩阵A上,此时若还用三元组表表示法,势必会为了保持三元组表“以行序为主序”而大量移动

6、元素。,在十字链表中,矩阵的每一个非零元素用一个结点表示, 该结点除了(row,col,value)以外,还要有以下两个链域: right: 用于链接同一行中的下一个非零元素;down: 用于链接同一列中的下一个非零元素。,图5.23 十字链表的结构,十字链表的结构类型说明如下:,typedef struct OLNode int row, col; /* 非零元素的行和列下标 */ ElementType value; struct OLNode * right, *down; /* 非零元素所在行表、列表的后继链域 */OLNode; *OLink; typedef struct OLin

7、k * row_head, *col_head; /* 行、 列链表的头指针向量 */ int m, n, len; /* 稀疏矩阵的行数、 列数、 非零元素的个数 */CrossList;,CreateCrossList (CrossList * M)/* 采用十字链表存储结构, 创建稀疏矩阵M */scanf(,else /* 寻找行表中的插入位置 */for(q=M-row_headi; q-right /* 完成插入 */ ,广 义 表,广义表,顾名思义,也是线性表的一种推广。广义表被广泛地应用于人工智能等领域的表处理语言LISP语言中。在LISP语言中,广义表是一种最基本的数据结构,

8、就连LISP 语言的程序也表示为一系列的广义表。,在第2章中, 线性表被定义为一个有限的序列(a1,a2,a3,an), 其中ai被限定为是单个数据元素。广义表也是n个数据元素(d1,d2,d3,dn)的有限序列,但不同的是,广义表中的di既可以是单个元素,还可以是一个广义表,通常记作: GL=(d1,d2,d3, ,dn)。GL是广义表的名字,通常广义表的名字用大写字母表示。n是广义表的长度。若其中di是一个广义表,则称di是广义表GL的子表。在广义表GL中,d1是广义表GL的表头,而广义表GL其余部分组成的表(d2,d3,dn)称为广义表的表尾。由此可见广义表的定义是递归定义的,因为在定义

9、广义表时又使用了广义表的概念。, D=()空表;其长度为零。 A=(a, (b, c) 表长度为2的广义表,其中第一个元素是单个数据a,第二个元素是一个子表(b,c)。 B=(A, A, D) 长度为3的广义表, 其前两个元素为表A, 第三个元素为空表D。 C=(a,C) 长度为2递归定义的广义表,C相当于无穷表C=(a,(a,(a,()。 #其中,A、B、C、D是广义表的名字。 下面以广义表A为例, 说明求表头、 表尾的操作: head(A)=a 表A的表头是a。tail(A)=(b, c) 表A的表尾是(b, c)。 广义表的表尾一定是一个表。,从上面的例子可以看出: (1) 广义表的元素

10、可以是子表,而子表还可以是子表由此可见,广义表是一个多层的结构。 (2) 广义表可以被其它广义表共享,如广义表B就共享表A。 在表B中不必列出表A的内容,只要通过子表的名称就可以引用该表。 (3) 广义表具有递归性, 如广义表C。,由于广义表GL=(d1,d2,d3,dn)中的数据元素既可以是单个元素,也可以是子表,因此对于广义表来说,我们难以用顺序存储结构来表示它,通常我们用链式存储结构来表示。表中的每个元素可用一个结点来表示。广义表中有两类结点:一类是单个元素结点;另一类是子表结点。 任何一个非空的广义表都可以分解成表头和表尾两部分,反之,一对确定的表头和表尾可以唯一地确定一个广义表。由此

11、,一个表结点可由三个域构成:标志域、指向表头的指针域和指向表尾的指针域。而元素结点只需要两个域:标志域和值域。,typedef enum ATOM, LIST ElemTag; /* ATOM0,表示原子;LIST1, 表示子表 */ typedef struct GLNode ElemTag tag; /* 标志位tag用来区别原子结点和表结点 */ union AtomType atom; /* 原子结点的值域atom */struct struct GLNode * hp, *tp; htp;/* 表结点的指针域htp, 包括表头指针域hp和表尾指针域tp */ atom_htp; /* atom_htp 是原子结点的值域atom和表结点的指针域htp的联合体域 */ *GList;,图5.25 广义表的另一种结点结构,表结点,原子结点,typedef enum ATOM, LIST ElemTag; /* ATOM0, 表示原子; LIST1, 表示子表 * / typedef struct GLNode ElemTag tag; union AtomType atom; struct GLNode * hp; atom_hp; /* atom-hp 是原子结点的值域atom和表结点的表头指针域hp的联合体域 */ struct GLNode * tp; *GList;,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 实用文档 > 统计图表

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报