基础知识
在使用三元组顺序表实现矩阵压缩存储时,三元组存放在连续的内存区域中,在进行矩阵运算时非零的元素可能变成零元素,非零元素会出现新值,此时需要移动数组中的三元组,对空间消耗是巨大的(本人三元组顺序表实现中直接开辟了一个新的数组),如果结合链表的优点,那么可以使用称为十字链表的数据结构,本文将实现之并完成矩阵常用的操作(可直接采用三元组顺序表中定义的操作)。
在实现十字链表压缩存储稀疏矩阵之前,预先定义十字链表三元组节点结构如下:
1 | template<typename DataType> |
上述结构和三元组顺序表最大的不同是增加了两个链接指针。
需要是实现的矩阵基本运算主要有:
- 矩阵转置:TransposeMatrix
- 矩阵加法:AddMatrix
- 矩阵减法:SubMatrix
- 矩阵乘法:MultiMatrix
- 打印矩阵:PrintMatrix
- 清空整个矩阵:MakeEmpty
十字链表基本定义
根据上述分析可定义如下基本ADT:
1 |
|
如上即为整个十字链表的ADT基本结构,基本仿照三元组顺序表中的定义,具体含义可见注释。接下来依次实现个函数。
三元组顺序表ADT的实现
- 构造函数
构造函数主要将二维存储的稀疏矩阵转变为十字链表矩阵。
1 | template<typename DataType> |
上述在定位插入点位置时可以进一步优化。
- 析构函数
析构主要释放创建十字链表节点时申请的空间,直接调用MakeEmpty函数即可,具体代码如下:
1 | template<typename DataType> |
- 矩阵转置
和三元组顺序表不同的是,十字链表转置只需交换节点内数据即可,具体代码如下:
1 |
|
- 矩阵相加
在进行矩阵加法,首先需要判断两个矩阵是否能够相加,然后我们也可以借鉴三元组顺序表的处理方式,不过我们在进行加法时按照行的顺序一行一行加并且保持一个列节点数组用来指定列插入的顺序以节省插入时间,具体实现代码如下:
1 | template<typename DataType> |
- 矩阵减法
将加法代码稍作修改即可:
1 | template<typename DataType> |
- 矩阵乘法
在进行矩阵乘法时,三元组顺序表需要一个额外的数组来快速定位行,而十字链表由于自身的特性可以快速寻址任意一行,因此在仿照三元组的顺序表乘法时可以简化一部分代码,但是乘法可能会改变矩阵列数,因此需要做一些特别的处理,具体见如下代码:
1 | template<typename DataType> |
- 压缩矩阵转成二维数组
直接按行遍历,具体代码如下所示:
1 | template<typename DataType> |
- 打印矩阵
先调用转二维函数然后直接打印即可,代码如下:
1 |
|
- 清空矩阵
一行一行释放空间,代码如下:
1 | template<typename DataType> |
代码测试
通过随机生成两个稀疏矩阵,然后依次测试各个函数是否正确,测试代码如下所示:
1 |
|