矩阵(Matrix)

特殊矩阵的存储

对称矩阵

在这里给出一组对称矩阵
这里写图片描述
因为其对称性,我们不需要存储其全部内容,只需要存储其下三角矩阵或者上三角矩阵。
在这里我选择存储下三角矩阵。
这里写图片描述
设矩阵的行数为M.
则需要存储的元素个数为 M(M+1)/2,以行优先进行存储。

当对此矩阵进行访问时,我们在内存中存储的数据应该是
这里写图片描述
当我们要访问第3行第2列(即i>=j)的元素时,便可以通过对其在存储的数据中的偏移量进行读取,偏移量即为该元素行之前的下三角的大小加上该元素所在列号。
当i

template<class T, int N>
class Matrix
{
public:
    Matrix(int arr[N][N])  //保存对称矩阵
    {
        int i = 0;
        int j = 0;
        int k = 0;
        _array.resize(N*(N + 1) / 2);
        for (i = 0; i < N; i++)     //行
        {
            for (j = 0; j <= i; j++)   //列
            {
                _array[k++] = arr[i][j];
            }
        }
    }
    void Print()  //打印
    {
        int i = 0;
        int j = 0;
        for (i = 0; i < N; i++)
        {
            for (j = 0; j < N; j++)
            {
                if (i >= j)
                    printf("%d ", _array[(i*(i + 1)) / 2 + j]);
                else
                    printf("%d ", _array[j*(j + 1) / 2 + i]);
            }
            cout << endl;
        }
    }
    template<class T, int N>
    friend ostream& operator <<(ostream &out, Matrix<T, N>&max)   //输出运算符重载
    {
        int i = 0;

        int j = 0;
        for (i = 0; i < N; i++)   //行
        {
            for (j = 0; j < N; j++)   //列
            {
                if (i >= j)
                    printf("%d ", max._array[(i*(i + 1)) / 2 + j]);
                else
                    printf("%d ", max._array[j*(j + 1) / 2 + i]);
            }
            cout << endl;
        }
        return out;
    }
    T& Access(int row, int col) {//访问矩阵
        if (col > row)
            swap(col, row);
        return _array[row*(row + 1) / 2 + col];
    }

private:
    vector<T> _array;
};
int main()
{
    int arr[5][5] =
    { { 0,1,2,3,4 },
    { 1,0,1,2,3 },
    { 2,1,0,1,2 },
    { 3,2,1,0,1 },
    { 4,3,2,1,0 } };        // 0 1 2 3 4 0 1 2 3 0 1 2 0 1 0
    Matrix<int, 5> max(arr);
    cout << max.Access(3, 2) << endl;
    cout << max.Access(2, 3) << endl;
    //cout << max << endl;
    max.Print();

    system("pause");
    return 0;
}

测试结果
这里写图片描述

稀疏矩阵

稀疏矩阵压缩存储

这里给出一组稀疏矩阵
这里写图片描述
因为其有效元素远远小于矩阵总元素,所以只需要保存其有效元素的位置信息与数据内容
在这里用一个结构体来保存有效元素的信息。

template<class T>
    struct Trituple //有效节点
    {
        Trituple()
        {}
        Trituple(int row, int col, T data)
            :_row(row)
            , _col(col)
            , _data(data)
        {}
        int _row;
        int _col;
        T _data;
    };

实现

template<class T, int M, int N>
class SparseMatrix
{
public:
    template<class T>
    struct Trituple //有效节点
    {
        Trituple()
        {}
        Trituple(int row, int col, T data)
            :_row(row)
            , _col(col)
            , _data(data)
        {}
        int _row;
        int _col;
        T _data;
    };
    SparseMatrix()
    {}
    SparseMatrix(int M, int N, T invalid)
        :_row(M)
        , _col(N)
        , _invalid(invalid)
    {}
    SparseMatrix(T arr[M][N],T invalid)  //保存稀疏矩阵
        :_row(M)
        ,_col(N)
        ,_invalid(invalid){
        int i = 0;
        int j = 0;
        for (i = 0; i < M; i++){
            for (j = 0; j < N; j++){
                if (arr[i][j] != _invalid){
                    Trituple<T> t(i,j,arr[i][j]);
                    _v.push_back(t);   //如果不是无效值 则存入
                }
            }
        }
    }
    void Print(){           //打印
        int i = 0;
        int j = 0;
        size_t index = 0;
        for (i = 0; i < _row; i++){
            for (j = 0; j < _col; j++){
                if (index < _v.size()){
                    if (_v[index]._row == i&&_v[index]._col == j) {
                        cout << _v[index]._data << " ";
                        index++;
                    }
                    else
                        cout << _invalid << " ";
                }
                else
                    cout << _invalid << " ";
            }
            cout << endl;
        }
    }
    template<class T,int M,int N>
    friend ostream& operator<<(ostream &out, SparseMatrix<T, M, N>&matrix)
    {
        int i = 0;
        int j = 0;
        size_t index = 0;
        for (i = 0; i < matrix._row; i++) {
            for (j = 0; j <matrix._col; j++) {
                if (index <matrix._v.size()) {
                    if (matrix._v[index]._row == i&&matrix._v[index]._col == j) {
                        cout << matrix._v[index]._data << " ";
                        index++;
                    }
                    else
                        cout << matrix._invalid << " ";
                }
                else
                    cout << matrix._invalid << " ";
            }
            cout << endl;
        }
        return out;
    }
public:
    vector<Trituple<T>> _v;  //保存有效节点
    int _row;
    int _col;
    T _invalid;
};

矩阵的逆置

将原矩阵的行和列进行交换,也就是将[i][j]交换为[j][i].
但是如果只是将有效节点表中的行和列交换会造成,因为首次存储时行优先的存储顺序造成结果无法完整输出。
这里写图片描述
此时若依然按照行优先顺序进行输出,则不能全部输出。
此时可以先依据行号进行排序,再将所有元素的行列进行交换。
(因为首次存储时一招行优先进行存储,所以排序交换后的元素也将是按照行优先的顺序排列的)
这里写图片描述
实现:

void InverseMatrix(){    //逆置矩阵
        size_t i = 0;
        size_t j = 0;
        size_t index = 0;
        for (index = 0; index < _v.size(); index++){    //先将里面的坐标交换
            swap(_v[index]._row,_v[index]._col);
        }
        swap(_row, _col);  
        for (i = 0; i < _v.size(); i++){  //排序
            for (j = i; j < _v.size() - 1; j++){
                if (_v[j]._row > _v[j + 1]._row){
                    swap(_v[j], _v[j + 1]);
                }
            }
        }

稀疏矩阵快速逆置

快速逆置
用两个数组 分别统计
1.转置后的矩阵每一行的参数个数
2.转置后矩阵每行元素在压缩矩阵中存储的开始位置
这里写图片描述
过程
这里写图片描述
这里写图片描述
实现

SparseMatrix& QuickInverseMatrix(){         //快速逆置
        int j = 0;
        int i = 0;
        size_t index = 0;
        int *RowCount = new int[N];
        memset(RowCount, 0, N*sizeof(int));
        for (; index < _v.size(); index++) {   //转置后的矩阵每一行的参数个数
            RowCount[_v[index]._col]++;

        }  // 2 0 2 0 2
        int *RowStart = new int[N];
        memset(RowStart, 0, N * sizeof(int));   //转置后矩阵每行在压缩矩阵中存储的开始位置
        for (i = 0; i < N; i++){
            if (i == 0)     // 第一行元素的偏移量永远为0
                RowStart[i] = 0;
            else {
                RowStart[i] = RowCount[i - 1] + RowStart[i - 1];
            }
        }   //0 2 2 4 4
        // 打印
        index = 0;
        SparseMatrix *sm=new SparseMatrix;
        sm->_row = _col;
        sm->_col = _row;
        sm->_v.resize(_v.size());
        for (size_t i = 0; i < _v.size();i++) {
            int &num = RowStart[_v[i]._col];
            sm->_v[num] = _v[i];
            swap(sm->_v[num]._row, sm->_v[num]._col);
            num++;
        }
        delete[]RowCount;
        delete[]RowStart;
        return *sm;
    } 

矩阵的加法

矩阵的简单运算—–加法

将两个矩阵中相同位置的元素进行加法运算(两个矩阵的行和列相同)。

这里写图片描述
因为我们存储时只存储有效元素,所以不能通过简单遍历的方式进行运算。
在用二维数组存储矩阵的时候,因为二维数组也是一个线性结构,所以可以根据有效元素在矩阵中的偏移量进行比较,如果偏移量不同,则将偏移量较小的元素放入,如果相同则进行加法运算。
这里写图片描述
实现

SparseMatrix& operator+(SparseMatrix&t) //矩阵加法
    {
        if (_col != t._col || _row != t._row)
        {
            exit(EXIT_FAILURE);
        }
        SparseMatrix*sm = new SparseMatrix(_row, _col, _invalid);
        size_t index1 = 0;
        size_t index2 = 0;

        //利用偏移量比较先后顺序
        while (index1<_v.size()&&index2<t._v.size())
        {
            if ((_v[index1]._row*_col+_v[index1]._col) < (t._v[index2]._row*_col + t._v[index2]._col))
            {//_v在前
                sm->_v.push_back(_v[index1]);
                index1++;
            }
            else if ((_v[index1]._row*_col + _v[index1]._col) > (t._v[index2]._row*_col + t._v[index2]._col))
            {//t._v 在前
                sm->_v.push_back(t._v[index2]);
                index2++;
            }
            else
            { //偏移量相同
                //Trituple *t = new Trituple(_row, _col, _v[index1]._data + t._v[index2]._data);
                Trituple<T> t1(_v[index1]._row,_v[index1]._col, _v[index1]._data + t._v[index2]._data);
                sm->_v.push_back(t1);
                index1++;
                index2++;
            }
        }
        while (index1 < _v.size()) {
            sm->_v.push_back(_v[index1]);
            index1++;
        }
        while (index2 < t._v.size()) {
            sm->_v.push_back(t._v[index2]);
            index2++;
        }

        return *sm;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值