特殊矩阵的第二种–>稀疏矩阵
稀疏矩阵是指矩阵中有效元素远远小于无效值的个数,大概比例就是:
有效值个数/无效值个数~0.05
所以,稀疏矩阵在存储时只需要保存有效元素的位置信息以及值,对于无效值只需要用_invalid来记录。
#include <iostream>
#include <windows.h>
#include <vector>
using namespace std;
template<class T>
class SparseMatrix
{
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;
};
public:
// 稀疏矩阵的压缩存储
SparseMatrix(int* arr, 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(arr[i*col+j] != invalid)
_vec.push_back(Trituple<T>(i, j, arr[i*col+j]));
}
}
}
SparseMatrix()
{}
// 访问稀疏矩阵中row行col中的元素
T& Access(int row, int col)
{
for(size_t i=0; i<_vec.size();++i)
{
if(row == _vec[i]._row && col == _vec[i]._col)
return _vec[i]._data;
}
return _invalid;
}
// 还原稀疏矩阵
template<class T>
friend ostream& operator<<(ostream& _cout, 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._vec.size() && s._vec[index]._row == i \
&& s._vec[index]._col ==j)
_cout<<s._vec[index++]._data<<" ";
else
_cout<<s._invalid<< " ";
}
cout<<endl;
}
return _cout;
}
// 实现稀疏矩阵的逆置,并给出时间复杂度
SparseMatrix<T> Transprot()
{
SparseMatrix<T> _sm;
_sm._row = _row;
_sm._col = _col;
_sm._invalid = _invalid;
for(size_t i=0; i<_col; ++i)
{
vector<Trituple<T>>::iterator it = _vec.begin();
while(it != _vec.end())
{
if(it->_col == i)
{
_sm._vec.push_back(Trituple<T>(it->_col, it->_row, it->_data));
}
++it;
}
}
return _sm;
}
// 实现稀疏矩阵的快速逆置,并给出时间复杂度
SparseMatrix<T> FastTransprot()
{
SparseMatrix<T> _sm;
_sm._row = _row;
_sm._col = _col;
_sm._invalid = _invalid;
_sm._vec.resize(_vec.size());
//先统计原矩阵中每队列的有效元素个数
int* pCount = new int[_col];
memset(pCount, 0, sizeof(pCount)*_col);
for(size_t i=0; i<_col; ++i)
{
pCount[_vec[i]._col]++;
}
//计算原矩阵中每一列在新矩阵中的起始位置
int* pAddr = new int[_col];
memset(pAddr, 0, sizeof(pAddr)*_col);
for(size_t i=1; i<_col; ++i)
{
pAddr[i] = pAddr[i-1] + pCount[i];
}
//放置新元素在新空间
for(size_t i=0; i<_col; ++i)
{
int& addr = pAddr[_vec[i]._col];
_sm._vec[addr] = Trituple<T>(_vec[i]._col, _vec[i]._row, _vec[i]._data);
addr++;
}
return _sm;
}
// 实现稀疏矩阵的加法操作
SparseMatrix<T> operator+(SparseMatrix<T>& sp)
{
SparseMatrix<T> _sm;
_sm._row = _row;
_sm._col = _col;
_sm._invalid = _invalid;
vector<Trituple<T>>::iterator it1 = _vec.begin();
vector<Trituple<T>>::iterator it2 = sp._vec.begin();
while(it1 != _vec.end()-1 || it2 != sp._vec.end()-1)
{
if(it1->_row == it2->_row)//先看是不是同一行的再比较列
{
if((it1->_col < it2->_col))//说明该行该列只有arr1存在有效值
{
_sm._vec.push_back(Trituple<T>(it1->_row, it1->_col, it1->_data));
++it1;
}
else if(it1->_col > it2->_col)//说明该行该列只有arr2存在有效值
{
_sm._vec.push_back(Trituple<T>(it2->_row, it2->_col, it2->_data));
++it2;
}
else//说明该行该列arr1和arr2都存在有效值,需要将_data相加后赋给_sm._vec._data;
{
if(it1->_data + it2->_data != 0)
_sm._vec.push_back(Trituple<T>(it1->_row, it1->_col, it1->_data+it2->_data));
++it1;
++it2;
}
}
else if(it1->_row > it2->_row)//说明该行只有arr2存在有效值
{
_sm._vec.push_back(Trituple<T>(it2->_row, it2->_col, it2->_data));
++it2;
}
else//说明该行只有arr1存在有效值
{
_sm._vec.push_back(Trituple<T>(it1->_row, it1->_col, it1->_data));
++it1;
}
}
while(it1 != _vec.end())//it1有剩余
{
_sm._vec.push_back(Trituple<T>(it1->_row, it1->_col, it1->_data));
++it1;
}
while(it2 != sp._vec.end())//it1有剩余
{
_sm._vec.push_back(Trituple<T>(it2->_row, it2->_col, it2->_data));
++it2;
}
return _sm;
}
private:
vector<Trituple<T>> _vec;
size_t _row;
size_t _col;
T _invalid;
};
int main()
{
int arr[][5] = {{1,0,3,0,5},
{0,0,0,0,0},
{0,0,0,0,0},
{1,0,3,0,5},
{0,3,0,0,0},
{0,0,0,0,0}};
int arr2[][5] = {{-1,0,3,0,5},
{0,0,2,0,0},
{0,1,0,0,0},
{1,0,3,0,5},
{1,0,0,4,0},
{0,0,0,0,0}};
SparseMatrix<int> s((int *)arr, sizeof(arr)/sizeof(arr[0]), sizeof(arr[0])/sizeof(arr[0][0]),0);
SparseMatrix<int> s2((int *)arr2, sizeof(arr2)/sizeof(arr2[0]), sizeof(arr2[0])/sizeof(arr2[0][0]),0);
cout<<"矩阵arr1"<<endl<<s;
cout<<"矩阵arr1"<<endl<<s2<<endl;
cout<<"矩阵arr1+arr2"<<endl<<s+s2;
//cout<<"逆置后打印"<<endl;
//cout<<s.FastTransprot();
system("pause");
return 0;
}
上面的矩阵加法是用一般的二维数组相加的方法,很麻烦,不仅要判断行,还要判断列。所以,可以将二维数组转换成一维数组进行计算。
二维数组在内存中的存储方式是按照一维数组来存储的,将二维数组的行又当做是一个一维数组,相当于是数组里面的元素又是一个数组。
SparseMatrix<T> operator+(SparseMatrix<T>& sp)
{
assert(_row == sp._row && _col == sp._col);
SparseMatrix<T> _sm;
_sm._row = _row;
_sm._col = _col;
_sm._invalid = _invalid;
int leftAddr = 0;
int Li = 0;
int rightAddr = 0;
int Ri = 0;
while(Li < _vec.size() && Ri<sp._vec.size())
{
leftAddr = _vec[Li]._row*_col + _vec[Li]._col;//将二维数组的下标转换成一维数组的下标
rightAddr = sp._vec[Ri]._row*_col + sp._vec[Ri]._col;
if(leftAddr < rightAddr)
{
_sm._vec.push_back(_vec[Li]);
Li++;
}
else if(leftAddr > rightAddr)
{
_sm._vec.push_back(sp._vec[Ri]);
Ri++;
}
else
{
Trituple<T> temp(_vec[Li]);
temp._data += sp._vec[Ri]._data;
if(temp._data != _invalid)
{
_sm._vec.push_back(temp);
}
Li++;
Ri++;
}
}
while(Li != _vec.size())//leftAddr有剩余
{
_sm._vec.push_back(_vec[Li++]);
}
while(Ri != sp._vec.size())//rightAddr有剩余
{
_sm._vec.push_back(sp._vec[Ri++]);
}
return _sm;
}