介绍两种矩阵,以及这两种矩阵压缩存储
并且使用C++实现它们
矩阵可以看为二维数组,存储与访问就和二维数组一样。
1.对称矩阵,如下图形式
此矩阵可以看为a[5][5]的二维数组行下标用i表示,列下标用j表示
很显然除对称轴以外的数据存储时同一个数据会存两遍,如果将相同的数存一遍,在矩阵很大的情况下就会节省很多的存储空间。
压缩存储数据就是只存储以对称轴分开的上三角或下三角的数据
也就是原来存N*N个数据,现在只存N*(N+1)/2个数据
对称矩阵中,只存了下三角的数据,下三角中有个特点就是i>=j,在访问上三角数据时,就可以转换为访问下三角数据
就是i和j交换。在访问某一特定的数据时,就可以利用二维数组的存储方式,得出:i*(i+1)/2+j
代码实现:
#pragma once
#include
#include
using namespace std;
template
class SymmetricMatrix
{
public:
SymmetricMatrix(int *a,size_t N)//带参构造函数
:_N(N)
{
_matrix = new T[N*(N + 1)/2];//申请空间
size_t index = 0;
for (size_t i = 0; i < N; ++i)
{
for (size_t j = 0; j < N; ++j)
{
//存入下三角数据
if (i >= j)
{
_matrix[index] = a[i*N + j];
++index;
}
else
break;
}
}
}
~SymmetricMatrix()//析构函数
{
delete[] _matrix;
_matrix = NULL;
_N = 0;
}
void Display()//打印矩阵
{
for (size_t i = 0; i < _N; ++i)
{
for (size_t j = 0; j < _N; ++j)
{
cout << Access(i,j) << " ";
}
cout << endl;
}
}
const T& Access(size_t i, size_t j) const//上三角元素转下三角
{
if (i < j)
swap(i, j);
return _matrix[i*(i + 1) / 2 + j];
}
protected:
T* _matrix;//压缩存储的一维数组
size_t _N;//N*N的矩阵
};
void SymmetricMatrixTest()//测试用例
{
int a[5][5] =
{
{ 0, 1, 2, 3, 4 },
{ 1, 0, 1, 2, 3 },
{ 2, 1, 0, 1, 2 },
{ 3, 2, 1, 0, 1 },
{ 4, 3, 2, 1, 0 },
};
SymmetricMatrix sm((int*)a,5);
sm.Display();
}
int main()
{
SymmetricMatrixTest();
return 0;
}
2.稀疏矩阵
稀疏矩阵的特点就是,一个矩阵里有效数据远小于无效数据,且没有规则。如:
稀疏矩阵的压缩:使用{row,col,value}三元组存储每一个有效 数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。
存放后就是:
矩阵的转置:就是行列对换,上面的矩阵经过转置后就变为:
转置后三元组的行优先,就可以转换成转置前的列优先。
转置还有一种更快的方式,就是快速转置。
快速转置就是对转置的优化,提高了时间复杂度,快速转置引入了两个变量记录每个有效的位置,直接进行存储,只遍历一次三元组的存储。
代码如下:
#pragma once
#include
#include
using namespace std;
template
struct Triple//三元组
{
size_t _row;//行
size_t _col;//列
T _value;//有效值
Triple(size_t row, size_t col, const T& value)//带参构造函数
:_row(row)
, _col(col)
, _value(value)
{}
Triple()//无参构造函数
{}
};
template
class SparseMatrix//稀疏矩阵
{
public:
SparseMatrix(T *a, size_t M, size_t N, const T& invalid = T())//带参构造函数
:_M(M)
, _N(N)
, _invalid(invalid)
{
for (size_t i = 0; i < M; ++i)
{
for (size_t j = 0; j < N; ++j)
{
if (a[i*N + j] != invalid)//找有效数据
{
Triple t(i, j, a[i*N + j]);
_matrix.push_back(t);//调用vector插入有效数据
}
}
}
}
SparseMatrix()//无参构造函数
{}
void Display()//打印矩阵
{
size_t index = 0;
for (size_t i = 0; i < _M; ++i)
{
for (size_t j = 0; j < _N; ++j)
{
if (index < _matrix.size() && _matrix[index]._row == i && _matrix[index]._col == j)//有效数据
{
cout << _matrix[index]._value << " ";
++index;
}
else//无效数据
{
cout << _invalid << " ";
}
}
cout << endl;
}
cout << endl;
}
SparseMatrix Transport()//转置
{
SparseMatrix sm;
sm._M = _N;
sm._N = _M;
sm._invalid = _invalid;
sm._matrix.reserve(_matrix.size());
for (size_t i = 0; i < _N; ++i)
{
for (size_t index = 0; index < _matrix.size(); ++index)
{
if (_matrix[index]._col == i)
{
Triple t( _matrix[index]._col, _matrix[index]._row,_matrix[index]._value);
/*Triple t(_matrix[index]);
swap(t._col, t._row);*/
sm._matrix.push_back(t);
}
}
}
return sm;
}
SparseMatrix FastTransport()//快速转置
{
SparseMatrix sm;
sm._M = _N;
sm._N = _M;
sm._invalid = _invalid;
sm._matrix.resize(_matrix.size());
int* count = new int[_N];
memset(count, 0, sizeof(int)*_N);
int* start = new int[_N];
for (size_t index = 0; index < _matrix.size(); ++index)
{
count[_matrix[index]._col]++;
}
start[0] = 0;
for (size_t i = 1; i < _N; ++i)
{
start[i] = start[i - 1] + count[i - 1];
}
for (size_t index = 0; index < _matrix.size(); ++index)
{
int row = _matrix[index]._col;
/*Triple t(_matrix[index]);
swap(t._col, t._row);*/
Triple t(_matrix[index]._col, _matrix[index]._row, _matrix[index]._value);
sm._matrix[start[row]] = t;
start[row] ++;
}
return sm;
}
protected:
vector> _matrix;
size_t _M;
size_t _N;
T _invalid;
};
void SparseMatrixTest()
{
int a[6][5] =
{
{ 1, 0, 0, 0, 5 },
{ 0, 3, 0, 4, 0 },
{ 0, 0, 0, 0, 0 },
{ 2, 0, 0, 0, 6 },
{ 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0 },
};
SparseMatrix sm((int*)a, 6, 5, 0);//稀疏矩阵
sm.Display();
SparseMatrix ret = sm.Transport();//转置矩阵
ret.Display();
SparseMatrix ret1 = sm.FastTransport();//快速转置矩阵
ret1.Display();
}
int main()
{
SparseMatrixTest();
return 0;
}