矩阵
对角矩阵的压缩存储
其实可以把下标看成当前位置之前的元素个数,如在一维数组中第n个元素 an-1 前面有 n-1 个元素,故前面有 k 个元素的下标就是 k。
这种看法和直接将 an-1 看成第 n 位在一维上没有什么区别,但个人觉得从直观理解的角度上来讲会更好。
对称矩阵的压缩存储是将二维转一维的过程,这里以下三角矩阵An*n进行描述,以 an-1,1 为例,对应于一维数组的下标:
- 先看行,n-1 代表 an-1,1 所在行前面有 n-1 行,因为取下三角进行压缩存储,行元素个数之间符合等比数列,所以总个数为:(n-1)*[1+(n-1)]/2 = n*(n-1)/2。
- 再看列,1 代表在该行中 an-1,1 前面有 1 个元素。
- 综上,可知 an-1,1 前有 n*(n-1)/2 +1 个元素,故对应于一维数组的下标为 n*(n-1)/2 + 1。
(当然,先理解为 an-1,1 为第 n*(n-1)/2 +2 个元素,再对应下标 -1 也可以,不过总感觉不直观。)
稀疏矩阵的存储
稀疏矩阵的存储方式分为顺序和链式,其实就是数组和链表,其中顺序存储方法有两种:三元组表示法和伪地址表示法,链式存储方法:邻接表表示法和十字链表表示法。
三元组
用数组第一个位置存储 [非零元素个数,总行数,总列数],其余位置存储 [值,行数,列数]。
结构和定义
/* 用数组会比结构体更方便些,下面先写结构体定义以帮助理解数组定义 */
typedef struct{
int val; /* 值 */
int i, j; /* 行/列号 */
}Trimat;
/* 两种定义,行定义为maxSize+1是因为第一行需要存储该矩阵的基本信息 */
Trimat trimat[maxSize+1];
int trimat_array[maxSize+1][3];
伪地址
和三元组类似,但仅使用一个量表示相对位置,将整个矩阵理解为行优先或者列优先的方式将下标转化为一维存储,这里和之前计算对称矩阵压缩很像,但不需要真将其转为一维,知道转化思路即可。
以行优先为例,Amxn矩阵的 Ai,j 项对应的下标为 i*n+j,其实已知下标 k 也可以反推,i = [k/n],j = k%n。
十字链表
邻接表在后面图中会详细阐述。
广义表
很像 SICP 中的序对,又或者说链表,广义表取表头对应于 SICP 的函数为 car(),表尾为 cdr()。