首先引入两个概念:
特殊矩阵:矩阵中很多值相同的元素并且它们的分布有一定的规律。
稀疏矩阵:矩阵中有很多零元素。
压缩存储的基本思想是:
⑴ 为多个值相同的元素只分配一个存储空间;
⑵ 对零元素不分配存储空间。
特殊矩阵的压缩存储——对称矩阵
在对角线的两边,aij==aji,这里出现了不必要的多于存储,所以我们对其进行矩阵的压缩。
这里只演示二维数组从0,0开始的
这分别是我们的二维数据中的下三角矩阵,和其保存为一维数组的存储说明图,下图更清楚地描述在一维数组里的结构:
首先假设一位数字的位置用k表示,二维数组用i、j表示,经过我们的推理不难发现,i、j、k之间存在一定的数量关系。
- a[i][j]在一维数组里的序号为=i*(i+1)/2+j+1
- a[i][j]在一维数组里的下标为=i*(i+1)/2+j
压缩对称矩阵的代码实现:
依旧是使用了刚才的那组数据,进行了压缩
#include<iostream>
using namespace std;
int main()
{
int a[5][5] = { 3,6,4,7,8,6,2,8,4,2,4,8,1,6,9,7,4,6,0,5,8,2,9,5,7 };
int n = 5, k = 0;
int b[15];
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
k = i * (i + 1) / 2 + j;
b[k] = a[i][j];
}
}
for (int i = 0; i < n * (n + 1) / 2; ++i)
{
cout << b[i] << " ";
}
return 0;
}
三角矩阵的压缩:
三角矩阵的样貌:
其实三角矩阵与对称矩阵有着很多类似的地方,比如如果是下三角矩阵,下三角的各个位置还是依旧对应着一维数组里的位置,唯一不同的是,一维数组还要再多加一个数据,就是上三角中相同的c。
一维数组存储图:
三角矩阵里i、j、k的对应关系:(依旧是从0,0开始)
这里以下三角矩阵为例进行代码演示:
c用0来代替
#include<iostream>
using namespace std;
int main()
{
int a[5][5] = { 3,0,0,0,0,6,2,0,0,0,4,8,1,0,0,7,4,6,0,0,8,2,9,5,7 };
int n = 5, k = 0;
int b[16];
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
k = i * (i + 1) / 2 + j;
b[k] = a[i][j];
}
}
b[15] = 0;
for (int i = 0; i <= n * (n + 1) / 2; ++i)
{
cout << b[i] << " ";
}
return 0;
}
对角矩阵的压缩
对角矩阵:所有非零元素都集中在以主对角线为中心的带状区域中,除了主对角线和它的上下方若干条对角线的元素外,所有其他元素都为零。
二维数组法:
把对角上的元素全部有序的整理在一个二位数组中,第一位和最后一位都是0,然后用一个新的b数组进行顺序存储。
原B上的数组下标与新B有着一定规律的对应关系,不难发现:t=i-1,s=j-i+1。
**一维数组的存储图:*一共3n-2个元素
i、j、k对应的关系:(略微复杂)
这里就不用代码实现了,纯粹就是一个找规律,但是自己确实不知道如何去找这个规律。这个对角矩阵的压缩的思想经过总结后,分为以下几步:
- 先把对角矩阵的相关数据取下来,保留原先的 i、j 下标不变。
- 将截取下来的二维数组变换下标,从0,0开始,使之成为一个顺序的二维数组。
- 把这个顺序的二维数组压缩成为一维数组进行保存。
下个周一定要做一次n=7的数组,取对角元素自己找一下规律训练一下。机器都会学习了,自己也要继续学习。
稀疏矩阵的压缩存储
稀疏矩阵的排列除了有部分值不为0之外,其他的值都是0,所以相比刚刚的对角矩阵,实现起来就友好很多。这里运用到了结构体类相关的知识,因为一个数据类型保存多个值。
这里引入三元组表的概念。
三元组表:将稀疏矩阵的非零元素对应的三元组所构成的集合,按行优先的顺序排列成一个线性表。
item代表这个元素值,row、col分别代表这个元素所在的位置。
template <class T>
struct element
{
int row, col; //行号,列号
T item //非零元素值
};
三元组表的存储说明:(三元组表最后的数据信息是整个矩阵的非零元素个数、行、列)
存储结构定义:
const int MaxTerm = 100;
template <class T>
struct SparseMatrix
{
T data[MaxTerm]; //存储非零元素
int mu, nu, tu; //行数,列数,非零元个数
};
同样,十字链表也可以表示稀疏矩阵的压缩
采用链接存储结构存储三元组表,每个非零元素对应的三元组存储为一个链表结点,结构为:
row:存储非零元素的行号
col:存储非零元素的列号
item:存储非零元素的值
right:指针域,指向同一行中的下一个三元组
down:指针域,指向同一列中的下一个三元组
template<class T>
class OLNode
{
private:
int row, col;
T element;
OLNode<T>* right, * down;
public:
OLNode() { right = NULL; down = NULL; };
};