没有经过处理的稀疏矩阵其实就是一个特殊的二维数组,数组中的大部分元素是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;
}
附完整代码:
/********************************************************************/
/*
实现稀疏矩阵的压缩存储
实现稀疏矩阵的三元组
利用容器存储三元组
实现稀疏矩阵的列序转置和快速转置
打印稀疏矩阵
By:Lynn-Zhang
*/
/********************************************************************/
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
#define ROW 6
#define COL 5
//三元组
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)
{}
};
template<class T>
class SparseMatrix
{
public:
SparseMatrix(); // 声明无参的构造函数
SparseMatrix(const T* array, size_t row, size_t col, const T& invalid); //构造函数初始化
SparseMatrix<T> Transport(); //转置
SparseMatrix<T> FastTranaport(); //快速转置
void Display(); //打印
protected:
vector<Triple<T>> _array; //利用容器压缩存储稀疏矩阵
size_t _rowMatrix; // 稀疏矩阵行数
size_t _colMatrix; // 稀疏矩阵列数
T _invalid; // 定义非法值
};
template<class T> //无参的构造函数
SparseMatrix<T>::SparseMatrix()
{}
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);
}
}
}
}
template<class T> //打印
void SparseMatrix<T>::Display() //打印
{
assert(_array.size()!=0);
size_t index = 0;
for (size_t i = 0; i < _rowMatrix; i++)
{
for (size_t j = 0; j < _colMatrix; ++j)
{
if (index < _array.size() && _array[index]._row == i&&_array[index]._col == j)
{
cout << _array[index]._value << " ";
index++;
}
else
{
cout << '0' << " ";
}
}
cout << endl;
}
cout << endl<<endl;
}
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;
}
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;
}
int main()
{
int array[ROW][COL] =
{
{ 1, 0, 3, 0, 5 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 1, 0, 3, 0, 5 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
SparseMatrix<int> sm((int*)array, ROW, COL, 0);
sm.Display();
SparseMatrix<int> sm1;
sm1 = sm.Transport();
cout << "转置后的矩阵为: " << endl << endl;
sm1.Display();
SparseMatrix<int> sm2;
sm2 = sm.FastTranaport();
cout << "快速转置后的矩阵为: " << endl << endl;
sm2.Display();
system("pause");
return 0;
}
转载于:https://blog.51cto.com/iynu17/1764327