数据结构之 矩阵---稀疏矩阵

来源:互联网 发布:xmind 8 mac 注册码 编辑:程序博客网 时间:2024/06/05 12:45

在之前的学习中,写了矩阵的模板类。但是很多情况下,并不是每一个元素都是非零的,当一个矩阵中的非零元素的较少的时候,其实是存在着空间的浪费的,于是,应该采用稀疏矩阵的方式来进行数据的保存和运算。
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");}

模板类的未测试函数在调用的时候还是可能连编译都通不过,这个是模板类编译的一个特点,后期需要研究。

原创粉丝点击