稀疏矩阵及稀疏矩阵的压缩存储
没有经过处理的稀疏矩阵其实就是一个特殊的二维数组,数组中的大部分元素是0或者其他类型的非法值,只有少数几个非零元素。
为了实现压缩存储,可以只存储稀疏矩阵的非0元素。在存储稀疏矩阵中的非0元素时,必须要存储该元素的行列号以及元素值。
我们可以封装一个三元组类来存储这些元素。
//三元组 template<class T> struct Triple { size_t _row; //行 size_t _col; //列 T _value; //值 Triple<T>::Triple() //定义无参的构造函数 {} Triple(size_t row, size_t col,T value) :_row(row) , _col(col) , _value(value) {} };
创建稀疏矩阵。利用容器,可以非常方便的存储这些元素,相当于用一个动态数组来存储。要求按照行优先的顺序存储,方便打印稀疏矩阵时,按照行列顺序依次打印非0元素。
template<class T> //利用容器实现稀疏矩阵的压缩存储 SparseMatrix<T>::SparseMatrix(const T* array, size_t row, size_t col, const T& invalid) //初始化 :_rowMatrix(row) , _colMatrix(col) ,_invalid(invalid) { for (size_t i = 0; i < _rowMatrix; ++i) { for (size_t j = 0; j < _colMatrix; ++j) { if (array[i*col + j] != invalid) { Triple<T> cur(i, j, array[i*col + j]); _array.push_back(cur); } } } }
列序转置法:以矩阵的列序进行转置,这样经过转置后得到的三元组容器序列正好是以行优先存储的。时间复杂度为 O(_colMatrix*_array.size())
template<class T> //列序转置 SparseMatrix<T> SparseMatrix<T>::Transport() { assert(_array.size()!=0); SparseMatrix<T> ret; ret._rowMatrix = _colMatrix; ret._colMatrix = _rowMatrix; ret._invalid = _invalid; ret._array.reserve(this->_array.size()); for (size_t j = 0; j < _colMatrix; j++) { size_t index = 0; while (index < _array.size()) { if (_array[index]._col == j) { Triple<T> tp(_array[index]._col, _array[index]._row, _array[index]._value); ret._array.push_back(tp); } index++; } if (this->_array.size() == ret._array.size()) { break; } } return ret; }
快速转置法:事先确定矩阵每一列第一个元素在容器中的位置,在对稀疏矩阵转置时,通过对原容器的遍历,依次直接将元素放在新容器的恰当位置。时间复杂度为O(_colMatrix+_array.size())
转置前,要先确定原矩阵每一列非零元素的个数,然后求出每一列非零元素在新容器中的正确位置。
设置两个整型数组RowCounts[_colMatrix]、RowStart[_colMatrix]分别用来存放三元组容器中每一列非零元素的个数以及每一列第一个非零元素在新容器中的正确位置。
RowStart[0] = 0; RowStart[col] = RowStart[col - 1] + RowCounts[col - 1];
列号 | 0 | 1 | 2 | 3 | 4 |
RowCounts[col] | 2 | 0 | 2 | 0 | 2 |
RowStart[col] | 0 | 2 | 2 | 4 | 4 |
template<class T> SparseMatrix<T> SparseMatrix<T>::FastTranaport() //快速转置 { assert(_array.size() != 0); size_t index = 0; SparseMatrix<T> ret; ret._rowMatrix = _colMatrix; ret._colMatrix = _rowMatrix; ret._invalid = _invalid; ret._array.resize(_array.size()); int *RowCounts = new int[_colMatrix]; int *RowStart = new int[_colMatrix]; memset(RowCounts, 0, _colMatrix*sizeof(int)); memset(RowStart, 0, _colMatrix*sizeof(int)); for (size_t i = 0; i < _array.size(); i++) { RowCounts[_array[i]._col]++; } RowStart[0] = 0; for (size_t i = 1; i < _colMatrix; i++) { RowStart[i] = RowStart[i - 1] + RowCounts[i - 1]; } Triple<T> tp; for (size_t i = 0; i < _array.size(); i++) { tp._row = _array[i]._col; tp._col = _array[i]._row; tp._value = _array[i]._value; ret._array[RowStart[_array[i]._col]++] = tp; } delete [] RowCounts; delete [] RowStart; return ret; }