对称矩阵与稀疏矩阵(转置)

来源:互联网 发布:网络文字编辑兼职 编辑:程序博客网 时间:2024/04/29 22:44

对称矩阵:n*n的方阵,对于矩阵的任意元素,aij=aji时(i和j都大于等于0小于n)
这里写图片描述
因为该矩阵的上三角和下三角的数据相同,为了节省空间,我们可以只存储下三角或上三角的元素,这种存储方式称为矩阵的压缩
矩阵压缩后的结构就可以是一个一维数组。
存储的个数是n*(n+1)/2(等差数列),任意元素在一维数组中是array[i*(i+1)/2+j];
对称矩阵的压缩储存

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<vector>using namespace std;template <class T> //对称矩阵的压缩class SymmetricMartic{public:    SymmetricMartic(T* a, size_t N)//将二维数组当成一维数组在一维数组        :_N(N)    {        _Martix = new T[N*(N + 1) / 2];//先给压缩矩阵开辟空间        size_t index = 0;        for (size_t i = 0; i < N; i++)        {            for (size_t j = 0; j < N; j++)            {                if (i >= j)//存储下三角                {                    _Martix[index++] = a[i*N + j];//把二维数组当成一维数组遍历a[i*N+j]                }                else                {                    break;                }            }        }    }    ~SymmetricMartic()    {        delete _Martix;        _Martix = NULL;        _N = 0;    }    void Display()    {        for (size_t i = 0; i<_N; i++)        {            for (size_t j = 0; j < _N; j++)            {                cout << Access(i, j) << " ";            }            cout << endl;        }        cout << endl;    }    const T& Access(size_t i,size_t j) const//实现一个接口,当还原上三角的元素是应在压缩矩阵存储的下三角寻找对应,将i,j交换,就可以找到对应元素    {        if (j > i)        {            swap(i,j);//交换i,j        }        return _Martix[i * (i + 1) / 2 + j];//返回(i,j)位置在压缩矩阵中对应位置元素    }    void fun()    {        for (size_t i = 0; i < _N*(_N+1)/2; i++)        {            cout << _Martix[i] << " ";        }        cout << endl;    }protected:    T* _Martix;//压缩存储的一维数组    size_t _N;//N*N矩阵};
void TestSymmetricMartic(){    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 },    };    SymmetricMartic<int> sm((int*)a, 5);    cout << "_Martix:";    sm.fun();    cout << endl;    sm.Display();}

结果
这里写图片描述
稀疏矩阵
M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据分布没有规律。
这里写图片描述
我们要先定义一个三元组Triple来存储元素及行列。

template <class T>struct Triple{    T _value;    size_t _row;    size_t _col;    Triple(size_t row=0, size_t col=0, const T& value=0)        : _row(row)        , _col(col)        , _value(value)    {}};

按行存储它的有效值,不知道需要开辟多大空间,这样就可以定义成一个vector,自己增容,将这些有效值push_back进去。

//稀疏矩阵template <class T>struct Triple{    T _value;    size_t _row;    size_t _col;    Triple(size_t row=0, size_t col=0, const T& value=0)        : _row(row)        , _col(col)        , _value(value)    {}};template<class T>class SparseMartix{public:    SparseMartix(T* a=0, size_t m=0, size_t n=0, const T& invalid=T())        :_rowsize(m)        , _colsize(n)        , _invalid(invalid)    {        for (size_t i = 0; i < m; i++)        {            for (size_t j = 0; j < n; j++)            {                if (a[i * n + j] != invalid)//判断是否是有效值                {                    Triple<T>  temp(i, j, a[i * n + j]);//构造一个三元组                    _a.push_back(temp);//插入到顺序表中                }            }        }    }    //遍历存储有效值三元组的vector如果有对应的i,j,将其直接打印,若没有打印invalid    void Display()    {        size_t index = 0;        for (size_t i = 0; i < _rowsize; i++)        {            for (size_t j = 0; j < _colsize; j++)            {                if (index<_a.size()&&_a[index]._row == i&&_a[index]._col == j)//遍历vector时它首先满足index<size()                {                    cout << _a[index]._value << " ";                    index++;                }                else                {                    cout << _invalid << " ";                }            }            cout << endl;        }        cout << endl;    }protected:    vector<Triple<T>> _a;    size_t _rowsize;    size_t _colsize;    T _invalid;};

接下来实现一下稀疏矩阵的转置:元素对应的i,j交换,aij–>aji

这里写图片描述
方法

第一种方法: 转置后的行对应转置前的列,用列(i)来遍历存储有效值的vector,在vector寻找第n列的元素,_a[index]._col==i,将push_back到一个新的vector sm,最后返回sm.
第二种方法:高效些,快速转置,快速定位。
这里写图片描述
代码实现:

//稀疏矩阵template <class T>struct Triple{    T _value;    size_t _row;    size_t _col;    Triple(size_t row=0, size_t col=0, const T& value=0)        : _row(row)        , _col(col)        , _value(value)    {}};template<class T>class SparseMartix{public:    SparseMartix(T* a=0, size_t m=0, size_t n=0, const T& invalid=T())        :_rowsize(m)        , _colsize(n)        , _invalid(invalid)    {        for (size_t i = 0; i < m; i++)        {            for (size_t j = 0; j < n; j++)            {                if (a[i * n + j] != invalid)//判断是否是有效值                {                    Triple<T>  temp(i, j, a[i * n + j]);//构造一个三元组                    _a.push_back(temp);//插入到顺序表中                }            }        }    }    //遍历存储有效值三元组的vector如果有对应的i,j,将其直接打印,若没有打印invalid    void Display()    {        size_t index = 0;        for (size_t i = 0; i < _rowsize; i++)        {            for (size_t j = 0; j < _colsize; j++)            {                if (index<_a.size()&&_a[index]._row == i&&_a[index]._col == j)//遍历vector时它首先满足index<size()                {                    cout << _a[index]._value << " ";                    index++;                }                else                {                    cout << _invalid << " ";                }            }            cout << endl;        }        cout << endl;    }    SparseMartix<T> Transport()//稀疏矩阵的转置    {        SparseMartix<T> sm;//转置后三元组内容        sm._colsize = _rowsize;        sm._rowsize = _colsize;        sm._invalid = _invalid;        for (size_t i = 0; i < _colsize; i++)//以列来遍历存储        {            size_t index = 0;            while (index < _a.size())            {                if (_a[index]._col == i)                {                     Triple<T> temp(_a[index]);//构造新的三元组内容,并且交换行列,插入sm中                    swap(temp._col, temp._row);                    sm._a.push_back(temp);                }                index++;            }        }        return sm;    }    SparseMartix<T> FastTransport()//稀疏矩阵的快速转置    {        SparseMartix<T> sm;        sm._colsize = _rowsize;        sm._rowsize = _colsize;        sm._invalid = _invalid;        sm._a.resize(_a.size());//定义数组count,start,开辟空间并初始化        int* count = new int[_colsize];        memset(count, 0, sizeof(int)*_colsize);        int* start = new int[_colsize];        size_t index = 0;        while (index < _a.size())//统计每一列的元素,以对应的列数作为count的下标        {            count[_a[index]._col]++;            index++;        }        start[0] = 0;        for (size_t i = 1; i < _colsize; i++)//算出start的值        {            start[i] = start[i - 1] + count[i - 1];        }        //快速定位        index = 0;        while (index < _a.size())        {            int row = _a[index]._col;//取出_a元素对应的列数            Triple<T> temp(_a[index]);            swap(temp._col, temp._row);            sm._a[start[row]] = temp;//列数在start对应的值就是在_a中的位置            start[row]++;            index++;        }        delete[] count;        delete[] start;        return sm;    }protected:    vector<Triple<T>> _a;    size_t _rowsize;    size_t _colsize;    T _invalid;};
//测试函数void TestSparseMartix(){    int a[6][5]=    {        { 1, 0, 3, 0, 5 },         { 0, 0, 0, 0, 0 },         { 0, 0, 0, 0, 0 },         { 2, 0, 4, 0, 6 },         { 0, 0, 0, 0, 0 },        { 0, 0, 0, 0, 0 }    };    SparseMartix<int> sm((int*)a, 6, 5, 0);    sm.Display();    SparseMartix<int> ret1 = sm.Transport();    ret1.Display();    SparseMartix<int> ret2 = sm.FastTransport();    ret2.Display();}
0 0
原创粉丝点击