在之前的学习中,写了矩阵的模板类。但是很多情况下,并不是每一个元素都是非零的,当一个矩阵中的非零元素的较少的时候,其实是存在着空间的浪费的,于是,应该采用稀疏矩阵的方式来进行数据的保存和运算。
11月1号将稀疏矩阵的内容写成了办完工状态,在注释中讨论到的顺序问题,还有待进一步的修改。
#ifndef _H_MY_SPARSE_MATRIX_H
#define _H_MY_SPARSE_MATRIX_H
#include <iostream>
#include <vector>
#include "myMatrix.cpp"
template<class T>
class sparseMatrix;
template<class T>
struct element
{
int row;
int col;
T val;
element(int r, int c, T v);
};
template<class T>
element<T>::element(int r, int c, T v)
{
row = r;
col = c;
val = v;
}
template<class T>
std::ostream& operator<<(std::ostream& out, sparseMatrix<T>& spm);
template<class T>
class sparseMatrix
{
public:
sparseMatrix(void);
sparseMatrix(myMatrix<T>& mat);
sparseMatrix(int row, int col);
sparseMatrix(sparseMatrix<T>& spm);
~sparseMatrix();
int cols(void){return m_col;}
int rows(void){return m_row;}
sparseMatrix<T>& operator=(sparseMatrix<T>& spm);
void transpose(void);
sparseMatrix<T> operator+(sparseMatrix<T>& spm);
void output(std::ostream& out);
private:
int m_row;
int m_col;
std::vector<struct element<T> > vec_ele;
};
template<class T>
sparseMatrix<T>::sparseMatrix(void)
{
m_row = -1;
while(m_row <= 0)
{
std::cout<<"\t请输入你矩阵的行数:";
std::cin>>m_row;
}
m_col = -1;
while(m_col <= 0)
{
std::cout<<"\t请输入你矩阵的列数:";
std::cin>>m_col;
}
int num = -1;
while (num < 0)
{
std::cout<<"\t请输入非零元素的数目:";
std::cin>>num;
}
for (int ii = 0; ii < num; ii++)
{
int row = -1;
int col = -1;
T val;
while (row <= 0 || row > m_row)
{
std::cout<<"\t请输入非零元素所在的行:";
std::cin>>row;
}
while (col <= 0 || col > m_col)
{
std::cout<<"\t请输入非零元素所在的行:";
std::cin>>col;
}
std::cout<<"\t请输入 "<<row<<" 行, "<<col<<" 列的非零元素:";
std::cin>>val;
vec_ele.push_back(struct element<T>(row,col,val));
}
}
template<class T>
sparseMatrix<T>::sparseMatrix(myMatrix<T>& mat)
{
m_row = mat.rows();
m_col = mat.cols();
vec_ele.clear();
for(int ii = 1; ii <= m_row; ii++)
{
for(int jj = 1; jj <= m_col; jj++)
{
if(mat(ii,jj) != 0)
{
vec_ele.push_back(struct element<T>(ii,jj,val));
}
}
}
}
template<class T>
sparseMatrix<T>::sparseMatrix(int row, int col)
{
m_row = row;
m_col = col;
vec_ele.clear();
}
template<class T>
sparseMatrix<T>::sparseMatrix(sparseMatrix<T>& spm)
{
m_col = spm.cols();
m_row = spm.rows();
vec_ele.clear();
for(std::vector<struct element<T> >::iterator it = spm.vec_ele.begin(); it != spm.vec_ele.end(); it++)
{
vec_ele.push_back(struct element<T>(it->row, it->col, it->val));
}
}
template<class T>
sparseMatrix<T>::~sparseMatrix()
{
vec_ele.clear();
}
template<class T>
sparseMatrix<T>& sparseMatrix<T>::operator=(sparseMatrix<T>& spm)
{
if(this != &spm)
{
m_row = spm.rows();
m_col = spm.cols();
vec_ele.clear();
for(std::vector<struct element<T> >::iterator it = spm.vec_ele.begin(); it != spm.vec_ele.end(); it++)
{
vec_ele.push_back(struct element<T>(it->row, it->col, it->val));
}
}
return (*this);
}
/这个转置的方法主要是为了保持行主排序,即使一个稀疏矩阵的元素没有按照行主的排序规则也没有关系的
template<class T>
void sparseMatrix<T>::transpose(void)
{
if()
int *colSize = new int[m_col];
int *colFirst = new int[m_col];
memset(colSize, 0, m_col * sizeof(int));
memset(colFirst, 0, m_col * sizeof(int));
for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++)
{
colSize[it->col - 1] = colSize[it->col - 1] + 1;
}
colFirst[0] = 0;
for (int ii = 1; ii < m_col; ii++)
{
colFirst[ii] = colFirst[ii - 1] + colSize[ii - 1];
}
std::vector<struct element<T> > vec_res;
for(std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++)
{
vec_res.insert(colFirst[it->col - 1],struct element<T>(it->col, it->row, it->val));
colFirst[it->col - 1] = colFirst[it->col - 1] + 1;
}
vec_ele = vec_res;
vec_res.clear();
}
template<class T>
sparseMatrix<T> sparseMatrix<T>::operator+(sparseMatrix<T>& spm)
{
if (m_col != spm.cols() || m_row != spm.rows())
{
throw("DimensionNotMatched");
}
sparseMatrix<T> spm_res(m_row, m_col);
std::vector<struct element<T> >::iterator itL = vec_ele.begin();
std::vector<struct element<T> >::iterator itLEnd = vec_ele.end();
std::vector<struct element<T> >::iterator itR = spm.vec_ele.begin();
std::vector<struct element<T> >::iterator itREnd = spm.vec_ele.end();
for(; itL != itLEnd && itR != itREnd; )
{
int indexL = (itL->row - 1) * m_col + itL->col - 1;
int indexR = (itR->row - 1) * m_col + itR->col - 1;
if(indexR == indexL)
{
T val = itR->val + itL->val;
if (val != 0)
{
spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, val));
}
itL ++;
itR++;
}
else if (indexL < indexR)
{
spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, itL->val));
itL++;
}
else
{
spm_res.vec_ele.push_back(struct element<T>(itR->row, itR->col, itR->val));
itR++;
}
}
for (; itL != itLEnd; itL++)
{
spm_res.vec_ele.push_back(struct element<T>(itL->row, itL->col, itL->val));
}
for (; itR != itREnd; itR++)
{
spm_res.vec_ele.push_back(struct element<T>(itR->row, itR->col, itR->val));
}
return spm_res;
}
template<class T>
void sparseMatrix<T>::output(std::ostream& out)
{
out<<std::endl;
for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++)
{
out<<"\t"<<it->row;
}
out<<std::endl;
for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++)
{
out<<"\t"<<it->col;
}
out<<std::endl;
for (std::vector<struct element<T> >::iterator it = vec_ele.begin(); it != vec_ele.end(); it++)
{
out<<"\t"<<it->val;
}
out<<std::endl;
}
/// 在测试重载操作符+和=的时候突然想到,是否是行主排序是很重要的。
/// 如果乱序可能会导致在求和的时候导致原来的值被覆盖
/// 比如一个3*3稀疏矩阵A,以行主排序的方式在向量中应该是11,13,23,33
/// 和另外一个3*3的稀疏矩阵B,以行主排序的方式排列应该也是11,13,23,33
/// 但是如果乱序之后,A变成11,33,13,23,B保持不变,11,13,23,33
/// 那么在重载的操作符+中,被求和的顺序则变成了
/// 11的两个求和,没问题,然后两个向量的迭代器都增加
/// 问题出现:B的迭代器换算的索引是2,A的迭代器换算的索引是8,那么认为B在前,是单独的,
/// 把B的值单独赋值进结果矩阵的13位置,然后迭代器增加,A的迭代器不改变,B指向23,换算出来的索引是5,还是比A的索引小
/// 仍旧B的值单独赋值到新的矩阵的23位置,然后B的迭代器增加,A不变,B变成33,好,两个迭代器相同了
/// 把计算结果赋值到33位置,这个也没有问题,然后两者的迭代器都增加,但是B到了迭代器的终点,A还在中间,
/// 指向13,然后把13位置的元素和23位置的元素替换为A中对应位置的值。
/// 所以,从上面的过程可以看出,一个错误的结果顺序会导致大量的元素的值为错误,
/// 或者,比如原来正常13和23的对应求和均为0,现在这种错误顺序会导致结果不为0,造成稀疏矩阵的元素个数不正确
template<class T>
std::ostream& operator<<(std::ostream& out, sparseMatrix<T>& spm)
{
spm.output(out);
return out;
}
#endif
下面的是使用的测试用例,仅仅测试了一些,没有完全测试,后面会补上。
#include <iostream>
#include "mySparseMatrix.cpp"
#include "myMatrix.cpp"
void main(void)
{
sparseMatrix<int> spm1;
std::cout<<spm1<<std::endl;
sparseMatrix<int> spm2;
std::cout<<spm2<<std::endl;
sparseMatrix<int> spm3(3,3);
spm3 = spm1 + spm2;
std::cout<<spm3<<std::endl;
std::system("pause");
}
模板类的未测试函数在调用的时候还是可能连编译都通不过,这个是模板类编译的一个特点,后期需要研究。