第6章串数组:特殊矩阵的压缩存储
6.6 特殊矩阵的压缩存储
在计算机科学中,用二维数组来表示数学中的矩阵,是最自然的方法。
有一类矩阵,其非零元素或者零元素的分布有一定规律,比如:对称矩阵、三角矩阵、对角矩阵等。为了节省存储空间,可以利用这类矩阵中元素的分布规律,为多个值相等的元素只分配一个存储空间,对零不分配空间。这就是所谓的压缩存储,从而可以提高存储空间利用率。
1. 对称矩阵
对于 nnn 阶方阵 A=(aij)n×n\pmb{A}=(a_{ij})_{n\times n}A=(aij)n×n ,位置索引值 i=ji=ji=j 的那些元素,构成了矩阵的主对角线(Main Diagonal)。
- i=ji=ji=j ,aija_{ij}aij 构成了主对角线元素;
- i<ji\lt ji<j ,aija_{ij}aij 构成了上三角部分元素;
- i>ji\gt ji>j ,aija_{ij}aij 构成了下三角部分元素;
[a11a12⋯a1na21a22⋯a2n⋮⋮⋱⋮an1an2⋯ann] \begin{bmatrix}a_{11}&a_{12}&\cdots&a_{1n}\\a_{21}&a_{22}&\cdots&a_{2n}\\\vdots&\vdots&\ddots&\vdots\\a_{n1}&a_{n2}&\cdots&a_{nn}\end{bmatrix} a11a21⋮an1a12a22⋮an2⋯⋯⋱⋯a1na2n⋮ann
以主对角线为对称轴,两侧元素对称分布的对角矩阵,即 aij=aji, i≠ja_{ij}=a_{ji},~i\ne jaij=aji, i=j ,这样的矩阵称为对称矩阵(Symmetric Matrix),即上三角部分和下三角部分中的对应元素相等。
如果将对称矩阵存储到一维的存储结构中,为了讲解和操作方便,用一维数组表示一维的存储结构,在 6.5 节中已经讲解过,如果将一维数组保存到内存中,该数组的元素和内存中的存储单元一一对应。所以,可以假设一维数组 BBB 作为 nnn 阶对称矩阵 A\pmb{A}A 的存储结构,A\pmb{A}A 中的元素 aija_{ij}aij 存储在 BBB 中的 bkb_kbk 处。
在存储对称矩阵时,可以只存储主对角线和上三角部分的元素,或者是主对角线和下三角部分的元素,让对称的两个元素共享一个存储空间。
不失一般性,根据对称矩阵的特点,采用以行序为主序,存储主对角线和下三角部分的元素,如图 6.6.1 所示。
下面探讨 kkk 与 i, ji,~ji, j 的关系(kkk 是从 0 开始;i,ji,ji,j 都是从 1 开始)。
(1)若 aija_{ij}aij 是 A\pmb{A}A 中主对角线或下三角部分的元素,则有 i≥ji\ge ji≥j (以行序为主序)。aija_{ij}aij 处于第 iii 行,那么在第 111 行到第 i−1i-1i−1 行中,需要保存如下元素:
-
第 1 行有 1 个元素:a11a_{11}a11
-
第 2 行有 2 个元素:a21,a22a_{21}, a_{22}a21,a22
-
⋯\cdots⋯
-
第 i−1i-1i−1 行有 i−1i-1i−1 个元素:a(i−1)1,a(i−1)2,⋯ ,a(i−1)(i−1)a_{(i-1)1},a_{(i-1)2},\cdots,a_{(i-1)(i-1)}a(i−1)1,a(i−1)2,⋯,a(i−1)(i−1)
以上共计元素数量:1+2+⋯+(i−1)1+2+\cdots+(i-1)1+2+⋯+(i−1)
- 在第 iii 行的元素 aij (j≤i)a_{ij}~(j\le i)aij (j≤i) 的前面的元素是:ai1,ai2,⋯ ,ai(j−1)a_{i1},a_{i2},\cdots,a_{i(j-1)}ai1,ai2,⋯,ai(j−1) ,共计有 j−1j-1j−1 个元素
综上,在 aija_{ij}aij 之前的元素总数量是:
[1+2+⋯+(i−1)]+(j−1)=i(i−1)2+(j−1)
[1+2+\cdots+(i-1)]+(j-1)=\frac{i(i-1)}{2}+(j-1)
[1+2+⋯+(i−1)]+(j−1)=2i(i−1)+(j−1)
由于 kkk 是从 0 开始,aija_{ij}aij 存储到 bkb_kbk 处,在 bkb_kbk 之前,数组 BBB 中共有 kkk 个元素,对应矩阵 A\pmb{A}A 中 aija_{ij}aij 之前的元素,所以则有:
k=i(i−1)2+(j−1), (i≥j)(1)
k = \frac{i(i-1)}{2}+(j-1),~(i\ge j)\tag{1}
k=2i(i−1)+(j−1), (i≥j)(1)
(2)若 aija_{ij}aij 是 A\pmb{A}A 中的上三角部分的元素,即 i<ji\lt ji<j ,其值与 ajia_{ji}aji 相等。根据(1)式,元素 ajia_{ji}aji 在数组 BBB 中对应的存储位置 bkb_kbk ,则此时 kkk 与 i, ji,~ji, j 的关系是:
k=j(j−1)2+(i−1), (i<j)(2)
k =\frac{j(j-1)}{2}+(i-1),~(i\lt j)\tag{2}
k=2j(j−1)+(i−1), (i<j)(2)
将(1)式和(2)式综合起来,得到 kkk 与 i,ji,ji,j 的关系如下:
k={i(i−1)2+(j−1), (i≥j)j(j−1)2+(i−1), (i<j)(3)
k=\begin{cases}\frac{i(i-1)}{2}+(j-1),~(i\ge j)\\\frac{j(j-1)}{2}+(i-1),~(i\lt j)\end{cases}\tag{3}
k={2i(i−1)+(j−1), (i≥j)2j(j−1)+(i−1), (i<j)(3)
作为存储对称矩阵的一维数组 BBB ,其空间大小应该是能够将主对角线和下三角部分的所有元素都存储于其中,即从第 1 行到第 nnn 行,总计存储的元素数量是:
1+2+⋯+n=n(n+1)2
1+2+\cdots+n=\frac{n(n+1)}{2}
1+2+⋯+n=2n(n+1)
数组 BBB 的分量从 0 开始编号,即 b0b_0b0 是第一个元素,则第 nnn 个元素的编号是 n(n+1)2−1\frac{n(n+1)}{2}-12n(n+1)−1 ,即 bn(n+1)/2−1b_{n(n+1)/2-1}bn(n+1)/2−1 是最后一个数组元素。
**重要方法归纳:**在计算矩阵 A\pmb{A}A 中元素 aija_{ij}aij 在数组 BBB 中存储位置 kkk 时,计算步骤如下:
- 求出元素 aija_{ij}aij 前面共存放多少个元素,假设为 mmm 个;
- 注意数组 BBB 存放元素的下标开始值,设下标开始值是 sss(一般是从 0 开始,有的从 1 开始)。
则 k=m+sk = m+sk=m+s 。
2. 三角矩阵
如果 nnn 阶矩阵的下三角部分的元素均为常数 ccc 或零,那么该矩阵称为上三角矩阵(Upper Triangular Matrix)。同样,矩阵的上三角部分的元素均为常数 ccc 或零,该矩阵称为下三角矩阵(Lower Triangular Matrix)。
对三角矩阵进行压缩存储,除了存储上三角或下三角部分以及主对角线的元素之外,另外还要存储常数 ccc 。所以,可以使用存储对称矩阵的思想,但是要对数组 BBB 在末端增加一个位置,用以存储常数 ccc 。
(1)下三角矩阵
如果将下三角部分和主对角线的元素,存储到一维数组 BBB 中,由对称矩阵的压缩存储可知,数组 BBB 中的元素个数是 n(n+1)2\frac{n(n+1)}{2}2n(n+1) ,如果 BBB 的下标是从 0 开始的,则最后一个元素的下标是 n(n+1)2−1\frac{n(n+1)}{2}-12n(n+1)−1;再加上另一部分的常数 ccc ,则可知,若将三角矩阵压缩到一维数组 BBB 中,需要 n(n+1)2+1\frac{n(n+1)}{2}+12n(n+1)+1 个位置,即数组 BBB 的下标范围是:0∼n(n+1)20\sim\frac{n(n+1)}{2}0∼2n(n+1) (含两端的值),如图 6.6.2 所示。
下面分析,以行序为主序,将 A\pmb{A}A 中的元素 aija_{ij}aij 存储到 BBB 的元素 bkb_kbk 中,kkk 和 i,ji,ji,j 的关系,其中,kkk 是从 0 开始,i,ji,ji,j 是从 1 开始。
-
若 aija_{ij}aij 是 A\pmb{A}A 中主对角线或下三角部分的元素,则有 i≥ji\ge ji≥j 。以行序为主序。
aija_{ij}aij 处于第 iii 行,那么在第 111 行到第 i−1i-1i−1 行中,需要保存如下元素:
-
第 1 行有 1 个元素:a11a_{11}a11
-
第 2 行有 2 个元素:a21,a22a_{21}, a_{22}a21,a22
-
⋯\cdots⋯
-
第 i−1i-1i−1 行有 i−1i-1i−1 个元素:a(i−1)1,a(i−1)2,⋯ ,a(i−1)(i−1)a_{(i-1)1},a_{(i-1)2},\cdots,a_{(i-1)(i-1)}a(i−1)1,a(i−1)2,⋯,a(i−1)(i−1)
-
在第 iii 行的元素 aij (j≤i)a_{ij}~(j\le i)aij (j≤i) 的前面的元素是:ai1,ai2,⋯ ,ai(j−1)a_{i1},a_{i2},\cdots,a_{i(j-1)}ai1,ai2,⋯,ai(j−1) ,共计有 j−1j-1j−1 个元素
综上,在 aija_{ij}aij 之前的元素总数量:
[1+2+⋯+(i−1)]+(j−1)=i(i−1)2+(j−1) [1+2+\cdots+(i-1)]+(j-1)=\frac{i(i-1)}{2}+(j-1) [1+2+⋯+(i−1)]+(j−1)=2i(i−1)+(j−1)
由于 kkk 是从 0 开始,aija_{ij}aij 存储到 bkb_kbk 处,在 bkb_kbk 之前,数组 BBB 中共有 kkk 个元素,对应矩阵 A\pmb{A}A 中 aija_{ij}aij 之前的元素,所以则有:
k=i(i−1)2+(j−1), (i≥j) k = \frac{i(i-1)}{2}+(j-1),~(i\ge j) k=2i(i−1)+(j−1), (i≥j) -
-
上三角部分的元素为常数 ccc ,即 i<ji\lt ji<j 时。用 BBB 中最后一个位置保存,即下标为 n(n+1)/2n(n+1)/2n(n+1)/2 的元素。
将以上两种情况合起来,得到 kkk 与 i,ji,ji,j 的关系:
k={i(i−1)2+(j−1),(i≥j)n(n+1)2,(i<j)(4)
k=\begin{cases}\frac{i(i-1)}{2}+(j-1),&&(i\ge j)\\\frac{n(n+1)}{2},&&(i\lt j)\end{cases}\tag{4}
k={2i(i−1)+(j−1),2n(n+1),(i≥j)(i<j)(4)
(2)上三角矩阵
对于上三角矩阵,也用类似的推导方法,得到 kkk 与 i,ji,ji,j 的关系。
总结:当三角矩阵 A\pmb{A}A 中的元素下标编号是从 1 开始的时候,即 i,ji,ji,j 从 1 开始计数,但数组 BBB 的 kkk 仍然是从 0 开始(数组的一般规定),那么数组 BBB 的下标 kkk 与三角矩阵的下标 i,ji,ji,j 的对应关系是:
上三角矩阵k={(i−1)(2n−i+2)2+(j−i),(i≤j)n(n+1)2,(i>j)下三角矩阵k={i(i−1)2+j−1,(i≥j)n(n+1)2,(i<j)(5)
\begin{split}
&\text{上三角矩阵}
\\&k=\begin{cases}\frac{(i-1)(2n-i+2)}{2}+(j-i),&&(i\le j)\\\frac{n(n+1)}{2},&&(i\gt j)\end{cases}
\\&\text{下三角矩阵}
\\&k=\begin{cases}\frac{i(i-1)}{2}+j-1,&&(i\ge j)\\\frac{n(n+1)}{2},&&(i\lt j)\end{cases}
\end{split}\tag{5}
上三角矩阵k={2(i−1)(2n−i+2)+(j−i),2n(n+1),(i≤j)(i>j)下三角矩阵k={2i(i−1)+j−1,2n(n+1),(i≥j)(i<j)(5)
3. 对角矩阵
若一个 nnn 阶方阵 A\pmb{A}A 满足其所有非零元素都集中在以主对角线为中心的带状区域中,则称此矩阵为 nnn 阶对角矩阵(Diagonal Matrix)。
对角矩阵主对角线上、下方各有 bbb 条非零元素构成的次对角线,称 bbb 矩阵半带宽,(2b+1)(2b+1)(2b+1) 为矩阵的带宽。
对于半带宽为 b (0≤b≤n−12)b~(0\le b\le\frac{n-1}{2})b (0≤b≤2n−1) 的对角矩阵,其 ∣i−j∣≤b|i-j|\le b∣i−j∣≤b 的元素 aija_{ij}aij 不为零,其余元素为零,即带宽之外的元素皆为零(如图 6.6.3 所示)。
如果 b=1b=1b=1 ,则得到如下所示的对角矩阵(为了显示清楚,这里以 5×55\times55×5 矩阵为例),该矩阵有一条主对角线和两条次对角线,故称为三对角矩阵。
A=[a11a12000a21a22a23000a32a33a34000a43a44a45000a54a55]
\pmb{A}=\begin{bmatrix}a_{11}&a_{12}&0&0&0\\a_{21}&a_{22}&a_{23}&0&0\\0&a_{32}&a_{33}&a_{34}&0\\0&0&a_{43}&a_{44}&a_{45}\\0&0&0&a_{54}&a_{55}\end{bmatrix}
A=a11a21000a12a22a32000a23a33a43000a34a44a54000a45a55
以三对角矩阵为例,对其以行序列主序进行压缩存储,只需要将其中的非零元素存储到一维数组 BBB 中,aija_{ij}aij 的对应存储位置是 bkb_kbk ,kkk 从 0 开始。
观察三角矩阵 A\pmb{A}A ,可以得知三角矩阵的如下特点:
- 行下标为 1 的行和行下标为 nnn 的行,都只有两个非零元素。
- 其他行各有三个非零元素。
对于行下标不为 1 的非零元素 aija_{ij}aij ,在其之前的非零元素包括:
-
行下标为 1 的行有 2 个非零元素;
-
从行下标 222 到行下标 i−1i-1i−1 的行,共计 i−2i-2i−2 行,每行 3 个非零元素,共计 3(i−2)3(i-2)3(i−2) 个元素
-
aija_{ij}aij 所在行的行下标为 iii ,aija_{ij}aij 之前的元素可能是:
-
若 aija_{ij}aij 是本行的第 1 个非零元素,则 aija_{ij}aij 之前的所有元素数量是:2+3(i−2)=3i−42+3(i-2)=3i-42+3(i−2)=3i−4 。并且此时,必然有 j=i−1j=i-1j=i−1 。所以 kkk 与 i,ji,ji,j 的关系为:
k=3i−4=2i+i−1−3=2i+j−3 k = 3i-4=2i+i-1-3=2i+j-3 k=3i−4=2i+i−1−3=2i+j−3 -
若 aija_{ij}aij 是本行的第 2 个非零元素,则 aija_{ij}aij 之前的所有元素数量是:2+3(i−2)+1=3i−32+3(i-2)+1=3i-32+3(i−2)+1=3i−3 。并且此时,必然有 i=ji=ji=j 。所以 kkk 与 i,ji,ji,j 的关系为:
k=3i−3=2i+i−3=2i+j−3 k = 3i-3=2i+i-3=2i+j-3 k=3i−3=2i+i−3=2i+j−3 -
若 aija_{ij}aij 是本行的第 3 个非零元素,则 aija_{ij}aij 之前的所有元素数量是:2+3(i−2)+2=3i−22+3(i-2)+2=3i-22+3(i−2)+2=3i−2 。并且此时,必然有 j=i+1j=i+1j=i+1 。所以 kkk 与 i,ji,ji,j 的关系为:
k=3i−2=2i+i+1−3=2i+j−3 k=3i-2=2i+i+1-3=2i+j-3 k=3i−2=2i+i+1−3=2i+j−3
-
综上可知,对于三对角矩阵而言,压缩存储的时候,数组中的位置 kkk 和矩阵的 i,ji,ji,j 关系是(i,ji,ji,j 是从 1 开始,kkk 从 0 开始):
k=2i+j−3(6)
k=2i+j-3\tag{6}
k=2i+j−3(6)
例 6.6.1 若对 n 阶对称矩阵 A\pmb{A}A 以行序为主序方式将其下三角形的元素(包括主对角线上所有元素)依次存放于一维数组 B[1..(n(n+1))/2]
中,则在 B 中确定 aij (i<j)a_{ij}~(i<j)aij (i<j) 的位置 k 的关系为( )。
A. i×(i−1)/2+ji\times(i-1)/2+ji×(i−1)/2+j\qquad B. j×(j−1)/2+ij\times(j-1)/2+ij×(j−1)/2+i\qquad C. i×(i+1)/2+ji\times(i+1)/2+ji×(i+1)/2+j\qquad D. j×(j+1)/2+ij\times(j+1)/2+ij×(j+1)/2+i
【解】
矩阵 A\pmb{A}A 是 nnn 阶对称矩阵,且元素 aija_{ij}aij 中的下标关系是 i<ji\lt ji<j ,说明此元素是上三角矩阵的一个元素。题目中要求以行序为主序的方式存储下三角的元素,则与 aija_{ij}aij 对称的是 ajia_{ji}aji ,aij=ajia_{ij}=a_{ji}aij=aji 。所以,本题转换为:确定 aji,(i≥j)a_{ji},(i\ge j)aji,(i≥j) 的位置 kkk 的关系。
根据以行序为主序的存储方式,存储对称矩阵的下三角(含对角线)不分,则第 1 行存储 a11a_{11}a11 ;第 2 行存储 a21,a22a_{21},a_{22}a21,a22 ;⋯\cdots⋯ ;第 (j−1)(j-1)(j−1) 行存储 a(j−1)1,⋯ ,a(j−1)(j−1)a_{(j-1)1},\cdots,a_{(j-1)(j-1)}a(j−1)1,⋯,a(j−1)(j−1) ;第 jjj 行存储 aj1,⋯ ,ajia_{j1},\cdots,a_{ji}aj1,⋯,aji 。将各行所存储的元素个数求和:
1+2+3+⋯+(j−1)+i=j×(j−1)2+i
1+2+3+\cdots+(j-1)+i=\frac{j\times(j-1)}{2}+i
1+2+3+⋯+(j−1)+i=2j×(j−1)+i
所以,k=j(j−1)2+ik=\frac{j(j-1)}{2}+ik=2j(j−1)+i 。
本题答案:B