首先稀疏矩阵的概念:
在一个矩阵中(并不要求为方阵)无效元素的个数远远大于有效元素的个数,我们称之为——稀疏矩阵。一般没有一个明确的界限分开稀疏矩阵和普通矩阵,不过一些人认为:有效元素的个数/无效元素的个数<0.05即可称之为稀疏矩阵。
跟对称矩阵压缩存储的逻辑相似:我们只需存储稀疏矩阵的有限元素就行,但有效元素的位置并没有什么规律,所以在存储时还要存储相应元素的行、列的下标。
可以用结构体实现:
template<class T>
struct Trituple
{
Trituple(size_t row, size_t col, const T& data)
: _row(row)
, _col(col)
, _data(data)
{}
Trituple()
{}
size_t _row;
size_t _col;
T _data;
};
则类中稀疏矩阵的成员应为:
private:
vector<Trituple<T>> _pData;
size_t _row;
size_t _col;
T _invalid;//无效元素的值
构造函数的实现很简单,我们只需要遍历一下这个矩阵,将不为无效值的元素的值、行和列存储就行。这里采用的方法也是讲二位数组转为一维数组进行访问。
SparseMatrix(int* array, size_t row, size_t col, const T& invalid)
: _row(row)
, _col(col)
, _invalid(invalid)
{
for (size_t i = 0; i < _row; i++)
{
for (size_t j = 0; j < _col; j++)
{
if (array[i*_col + j] != _invalid)
_pData.push_back(Trituple<T>(i, j, array[i*_col + j]));
}
}
}
稀疏矩阵的访问:
只需判断需要访问的行、列在压缩保存的一维数组中有没有对应的元素,如果有,则输出该值;如果没有,则输出无效值。
T& Access(int row, int col)
{
for (size_t i = 0; i < _pData.size();++i)
{
if (_pData[i]._row == row&&_pData[i]._col == col)
return _pData[i]._data;
}
return _invalid;
}
稀疏矩阵的还原输出:
同样,我们只需判断要访问的位置是否存在有效元素,有则输出,无则输出无效元素。此时我们最好不要直接访问Acess()函数,这样的话开销太大,时间复杂度过高,不是一个优秀的代码。所以我们使用vector中的迭代器访问被压缩存储的每一个元素。或者每次进入之后判断行、列的关系。
template<class T>
friend ostream& operator<<(ostream& os, SparseMatrix<T>& s)
{
size_t index = 0;
for (size_t i = 0; i < s._row; ++i)
{
for (size_t j = 0; j < s._col; ++j)
{
if ((index < s._pData.size()) && (s._pData[index]._row == i) && (s._pData[index]._col == j))
//注意:index<s._pData.size()是为了index访问不越界。
os << setw(3) << s._pData[index++]._data << " ";
else
os << setw(3) << s._invalid << " ";
}
os << endl;
}
return os;
}
稀疏矩阵的普通逆置:
按列访问,每一次进入之后判断压缩存储的一维数组中是否有对应列的元素,有的话,输出到新空间,并且向后移动。
SparseMatrix<T> Transprot()
{
SparseMatrix<T> temp;
temp._row = _col;
temp._col = _row;
for (size_t i = 0; i <