欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对称矩阵及稀疏矩阵浅谈

程序员文章站 2022-03-16 18:53:04
...

1.对称矩阵

特点:
关于对角线对称,Aij == Aji。
下面实现:
①对称矩阵的压缩存储
②对称矩阵的访问
③对称矩阵的还原

实现代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//对称矩阵的压缩存储
template<class T>
class SymmetricMatrix
{
public:
    SymmetricMatrix(T* array, size_t N)
        :_N(N)
        ,_a(NULL)
    {
        _a = new T[(N * (N + 1))>> 1];
        for (size_t i = 0; i < N; ++i)
        {
            for (size_t j = 0; j < N; ++j)
            {
                if (i >= j)//表明是下三角数据时
                {
                    _a[(i * (i + 1))>>1 + j] = array[i * N + j];
                }
                else
                {
                    break;
                }
            }
        }
    }

    T& Access(size_t x, size_t y)
    {
        if (x < y)//如果访问上三角元素
        {
            swap(x, y);
        }
        return _a[(x * (x + 1)) >> 1 + y];
    }

    void DisPlay()
    {
        for (size_t i = 0; i < _N; ++i)
        {
            for (size_t j = 0; j < _N; ++j)
            {
                if (i >= j)//访问下三角元素
                {
                    cout<<Access(i, j)<<" ";
                }
                else
                {
                    cout << Access(j, i) << " ";
                }
            }
            cout << endl;
        }
        cout << endl;
    }

    ~SymmetricMatrix()
    {
        if (_a)
        {
            delete[] _a;
            _a = NULL;
        }
    }

private:
    T* _a;
    size_t _N;
};

测试代码如下:

void Test()
{
    int a[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 },
    };
    SymmetricMatrix<int> sm((int*)a, 5);
    cout << sm.Access(0, 3) << endl;
    cout << sm.Access(3, 0) << endl;
    sm.DisPlay();
}

int main()
{
    Test();
    return 0;
}

2.稀疏矩阵:

对称矩阵及稀疏矩阵浅谈

(1)稀疏矩阵的压缩存储:

所谓稀疏矩阵的压缩存储,其实就是将稀疏矩阵中的有效元素保存起来,但由于稀疏矩阵中有效元素的分布没有规律可寻,所以需要使用一个三元组来保存其位置(row、col)以及有效值。—>三元组最好使用结构体来存储。

因为不知道矩阵中究竟有多少个有效元素(即就是不知需要多少个结构体),那么就可以使用vector(动态增长型)来保存有效元素。

//三元组--->存储有效元素的位置及值
    template<class T>
    struct Trituple
    {
        Trituple(size_t row, size_t col, const T& data)
        :_row(row)
        , _col(col)
        , _data(data)
        {}

        size_t _row;
        size_t _col;
        T _data;
    };
//稀疏矩阵的压缩存储
    SparseMatrix(T* array, int row, int col,const T& invalid)
        :_row(row)
        , _col(col)
        ,_invalid(invalid)
    {
        for (int i = 0; i < row; ++i)
        {
            for (int j = 0; j < col; ++j)
            {
                if (array[i * col + j] != invalid)
                {
                    _sm.push_back(Trituple<T>(i, j, array[i * col + j]));
                }
            }
        }
    }

(2)稀疏矩阵的转置:

对称矩阵及稀疏矩阵浅谈

稀疏矩阵的转置过程如下:

对称矩阵及稀疏矩阵浅谈

实现代码如下:

   // 稀疏矩阵的转置
   //时间复杂度:(稀疏矩阵的列*稀疏矩阵中有效元素的个数)
    SparseMatrix<T> Transprot()
    {
        SparseMatrix<T> sm;
        sm._row = _col;
        sm._col = _row;

        for (size_t index = 0; index < _col; ++index)
        {
            vector<Trituple<T> >::iterator it = _sm.begin();
            while (it != _sm.end())
            {
                if ( it->_col == index)
                {
                    sm._sm.push_back(Trituple<T>(it->_col, it->_row, it->_data));
                }
                it++;
            }
        }
        return sm;
    }

3.稀疏矩阵的快速转置:

稀疏矩阵的转置的时间复杂度:(稀疏矩阵的列N*稀疏矩阵中有效元素的个数)—-》时间复杂度较大,所以引出了快速转置

稀疏矩阵的快速转置的时间复杂度(2*有效元素的个数 + 稀疏矩阵的列)

快速转置的思想如下:

对称矩阵及稀疏矩阵浅谈

代码实现:


//快速转置
SparseMatrix<T,N,M> FastTransport(const size_t m,const size_t n)
    {
    SparseMatrix < T, N, M> sm;//转置后的压缩矩阵
        sm._row = _col;
        sm._col = _row;
        sm._v.resize(_v.size());//为了保证后面可以直接访问vector中的数据(调用operator[])
        //保存转置前的每列有效元素的个数,即就是转置后每行有效元素的个数
        int rows[N] = {0};
        size_t index = 0;
        while (index < _v.size())
        {
            rows[_v[index]._col]++;
            index++;
        }
        //保存转置后的每行第一个有效元素在转置后的三元组数组中的下标
        int starts[N] = { 0 };
        for (size_t i = 1; i < _col; ++i)
        {
            starts[i] = starts[i - 1] + rows[i - 1];
        }

        for (size_t i = 0; i < _v.size(); ++i)
        {
            int row = _v[i]._col;//转置前列的下标即是转置后行的下标
            Triple<T> t;
            t._value = _v[i]._value;
            t._col = _v[i]._row;
            t._row = _v[i]._col;
            sm._v[starts[row]] = t;
            starts[row]++;//每次需要更新starts数组中的数据
        }
        return sm;
    }

全部代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<vector>

//三元组
template<class T>
struct Triple
{
    Triple()
    {}
    Triple(T& data, size_t row, size_t col)
        :_value(data)
        , _row(row)
        , _col(col)
    {}
    T _value;
    size_t _row;
    size_t _col;
};

template<class T,size_t M,size_t N>
class SparseMatrix
{
public:
    SparseMatrix()
    {}

    //稀疏矩阵的压缩存储
    SparseMatrix(T* array, const T& invalid)
        :_invalid(invalid)
        , _row(M)
        , _col(N)
    {
        for (size_t i = 0; i < _row; ++i)
        {
            for (size_t j = 0; j < _col; ++j)
            {
                if (array[i * N + j] != invalid)
                {
                    Triple<T> t;
                    t._value = array[i * N + j];
                    t._row = i;
                    t._col = j;
                    _v.push_back(t);
                }
            }
        }
    }

    //稀疏矩阵的还原
    void Display()
    {
        int index = 0;
        for (size_t i = 0; i < _row; ++i)
        {
            for (size_t j = 0; j < _col; ++j)
            {
                if (index < _v.size() && _v[index]._row == i && _v[index]._col == j)
                {
                    cout << _v[index]._value << " ";
                    index++;
                }
                else
                {
                    cout << _invalid << " ";
                }
            }
            cout << endl;
        }
        cout << endl;
    }

    //稀疏矩阵的转置
    SparseMatrix<T,N,M> Transport()
    {
        SparseMatrix<T,N,M> _sm;//转置后的
        _sm._invalid = _invalid;
        _sm._row = _col;
        _sm._col = _row;
        //按列查找(转置前的列优先即就是转置后的行优先)
        for (size_t i = 0; i < _col; ++i)
        {
            size_t index = 0;
            while (index < _v.size())
            {
                if (_v[index]._col == i)
                {
                    Triple<T> t;
                    t._value = _v[index]._value;
                    t._row = _v[index]._col;
                    t._col = _v[index]._row;
                    _sm._v.push_back(t);
                }
                index++;
            }
        }
        return _sm;
    }

    template<class T, size_t N, size_t M>
    friend class SparseMatrix;

//快速转置
SparseMatrix<T,N,M> FastTransport(const size_t m,const size_t n)
    {
    SparseMatrix < T, N, M> _sm;//转置后的压缩矩阵
        _sm._row = _col;
        _sm._col = _row;
        _sm._v.resize(_v.size());//为了保证后面可以直接访问vector中的数据(使用operator[])
        //保存转置前的每列有效元素的个数,即就是转置后每行有效元素的个数
        int rows[N] = {0};
        size_t index = 0;
        while (index < _v.size())
        {
            rows[_v[index]._col]++;
            index++;
        }
        //保存转置后的每行第一个有效元素在转置后的三元组数组中的下标
        int starts[N] = { 0 };
        for (size_t i = 1; i < _col; ++i)
        {
            starts[i] = starts[i - 1] + rows[i - 1];
        }

        for (size_t i = 0; i < _v.size(); ++i)
        {
            int row = _v[i]._col;//转置前列的下标即是转置后行的下标
            Triple<T> t;
            t._value = _v[i]._value;
            t._col = _v[i]._row;
            t._row = _v[i]._col;
            _sm._v[starts[row]] = t;
            starts[row]++;//每次需要更新starts数组中的数据
        }
        return _sm;
    }

private:
    vector<Triple<T> >  _v;
    T _invalid;
    size_t _row;
    size_t _col;
};

测试代码如下:


void Test()
{
    int array[6][5] = { 
    { 1, 0, 3, 0, 5 },
    { 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0 },
    { 1, 0, 3, 0, 5 },
    { 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0 },
    };
    SparseMatrix<int,6,5> sm((int*)array, 0);
    sm.Display();
    SparseMatrix<int,5,6> sm2 = sm.FastTransport(5,6);
    sm2.Display();
}

int main()
{
    Test();
    return 0;
}

由于能力有限,又是刚开始学习数据结构,难免会有思考的不正确或是不完善的地方,欢迎大家批评指正。。。

相关标签: 矩阵