概述
矩阵是很多工程领域都需要的数学对象,在数据结构中主要讨论的是如何高效的存储矩阵的元(即矩阵中的元素)。
比如在矩阵的实际应用中,经常出现很多高阶矩阵存在很多相同元素或是0,为了节省空间就可以对其进行压缩,即多元素共享一个存储单元、不对0分配存储单元等。
假如值相同的元素或者零元素在矩阵中分布有一定规律,则称此类矩阵为特殊矩阵;反之则成为稀疏矩阵。下面分别看一下它们如何实现压缩存储。
特殊矩阵
若 n n n阶矩阵 A A A中的元满足性质: a i j = a j i ∣ 1 ≤ ( i , j ) ≤ n a_{ij} = a_{ji} \quad | \quad 1\leq (i, j) \leq n aij=aji∣1≤(i,j)≤n,则称为 n n n阶对称矩阵。
对于对称矩阵而言,可以为每一对对称元只分配一个存储空间,这样一来 n 2 n^2 n2个元就被压缩成了 n ( n + 1 ) / 2 n(n+1) /2 n(n+1)/2个元的空间中。
我们可以以行序为主序存储其下三角(包括对角线)的元。假设以一维数组
s
a
[
n
(
n
+
1
)
/
2
]
sa[n(n+1)/2]
sa[n(n+1)/2]作为
n
n
n阶对称矩阵
A
A
A的存储结构,则
s
a
[
k
]
sa[k]
sa[k]和矩阵元
a
i
j
a_{ij}
aij之间存着一一对应关系:
k
=
{
i
(
i
−
1
)
2
+
j
−
1
∣
i
≥
j
j
(
j
−
1
)
2
+
i
−
1
∣
i
<
j
k = \begin{cases} \frac{i(i-1)}{2}+j-1 \quad |& i \geq j\\ \frac{j(j-1)}{2}+i-1 \quad |& i < j \end{cases}
k={2i(i−1)+j−1∣2j(j−1)+i−1∣i≥ji<j
对于任意给定的下标(i,j)
,均可在
s
a
sa
sa中找到矩阵元
a
i
j
a_{ij}
aij。反之,对所有的
k
=
0
,
1
,
2
,
…
,
n
(
n
+
1
)
2
−
1
k=0,1,2, \dots, \frac{n(n+1)}{2}-1
k=0,1,2,…,2n(n+1)−1 ,都能确定
s
a
[
k
]
sa[k]
sa[k]中的元位于矩阵中的(i,j)
。
s
a
[
n
(
n
+
1
)
/
2
]
sa[n(n+1)/2]
sa[n(n+1)/2]可以称为
n
n
n阶对称矩阵
A
A
A的压缩存储。这种存储方法同样可以用于三角矩阵。
稀疏矩阵
稀疏矩阵没有精确的定义,但有一个数值可以计算:
设在 m × n m \times n m×n的矩阵中有 t t t个元素不为零,定 δ = t m n \delta = \frac{t}{mn} δ=mnt,称 δ \delta δ为矩阵的稀疏因子,通常认为 δ ≤ 0.05 \delta \leq 0.05 δ≤0.05时为稀疏矩阵。
对于稀疏矩阵,存储有不同的方式,可以采用三元组( i , j , a i j i, j, a_{ij} i,j,aij)顺序存储或是十字链表等方式。
三元组是用矩阵坐标及该位置元素存储的,即每个三元组对应矩阵中的一个元。有矩阵M如下:
M
=
[
0
12
9
0
0
0
0
0
0
0
0
0
−
3
0
0
0
0
14
0
0
24
0
0
0
0
18
0
0
0
0
15
0
0
−
7
0
0
]
M= \begin {bmatrix} 0& 12& 9& 0& 0& 0\\ 0& 0& 0& 0& 0& 0\\ -3& 0& 0& 0& 0& 14\\ 0& 0& 24& 0& 0& 0\\ 0& 18& 0& 0& 0& 0\\ 15& 0& 0& -7& 0& 0 \end {bmatrix}
M=⎣⎢⎢⎢⎢⎢⎢⎡00−3001512000180900240000000−70000000014000⎦⎥⎥⎥⎥⎥⎥⎤
则其对应的三元组即为
[
(
1
,
2
,
12
)
,
(
1
,
3
,
12
)
,
(
3
,
1
,
−
3
)
,
(
3
,
6
,
14
)
,
(
4
,
3
,
24
)
,
(
5
,
2
,
18
)
,
(
6
,
1
,
15
)
,
(
6
,
4
,
−
7
)
]
[(1,2, 12), (1,3, 12), (3,1, -3), (3,6, 14), (4,3, 24), (5,2, 18), (6,1, 15), (6,4, -7)]
[(1,2,12),(1,3,12),(3,1,−3),(3,6,14),(4,3,24),(5,2,18),(6,1,15),(6,4,−7)]。
三元组的缺点在于当矩阵元插入时,可能需要大量的移动操作,因此也有十字链表的方式存储,这样一来就可以避免操作时需要耗费大量时间来移动三元组了,如下图:
图片来自互联网