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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值