特殊矩阵之稀疏矩阵

特殊矩阵的第二种–>稀疏矩阵
稀疏矩阵是指矩阵中有效元素远远小于无效值的个数,大概比例就是:
有效值个数/无效值个数~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;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值