矩阵及其压缩存储

一.对称矩阵及对称矩阵的压缩存储
1.对称矩阵:设一个N*N的方阵A,A中任意元素Aij,当且仅当Aij == Aji(0 <= i <= N-1 && 0 <= j <= N-1),则矩阵A是对称矩阵。以矩阵的对角线为分隔,分为上三 角和下三角。
2.压缩存储称矩阵存储时只需要存储上三角/下三角的数据,所以最多存 储n(n+1)/2个数据。 对称矩阵和压缩存储的对应关系:下三角存储i>=j,SymmetricMatrix[i][j] == Array[i*(i+1)/2+j]

这里写图片描述

3.代码测试:

#include<iostream>
using namespace std;
#include<vector>

//对称矩阵
template<class T>
class SymmetricMatrix
{
public:
    SymmetricMatrix(T* a, size_t n)
        :_a(new T[n*(n + 1) / 2])
        , _n(n)
    {
        size_t index = 0;
        for (size_t i = 0; i < n; i++)
        {
            for (size_t j = 0; j < n; j++)
            {
                if (i >= j)//下三角
                {
                    _a[index++] = a[i*n + j];
                }
                else
                {
                    break;
                }
            }
        }
    }

    T& Access(size_t i, size_t j)
    {
        if (i >= j)
        {
            return _a[i*(i + 1) / 2 + j];
        }
        else
        {
            swap(i, j);
            return _a[i*(i + 1) / 2 + j];
        }
    }
    void Disply()
    {
        for (size_t i = 0; i < _n; i++)
        {
            for (size_t j = 0; j < _n; j++)
            {
                cout << Access(i, j) << " ";
            }
            cout << endl;
        }
        cout << endl;
    }
protected:
    T* _a;
    size_t _n;
};

void TestSymmetricMatrix()
{
    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> s((int*)a, 5);
    s.Disply();
}

int main()
{
    //TestSymmetricMatrix();
    TestSparseMatrix();
    system("pause");
    return 0;
}

这里写图片描述

二.稀疏矩阵
1.稀疏矩阵:M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没 有规律。
2.稀疏矩阵的压缩存储: 压缩存储值存储极少数的有效数据。使用{row,col,value}三元组存储每一个有效 数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。

这里写图片描述

3.代码测试:

//稀疏矩阵
template<class T>
struct Triple
{
    Triple(size_t r,size_t c,T& value)
        :_r(r)
        , _c(c)
        , _value(value)
    {}
    Triple()
    {}
    T _value;
    size_t _r;
    size_t _c;
};

template<class T>
class SparseMatrix
{
public:
    class SparseMatrix(T* a,size_t row,size_t col,const T& invalid)
        :_a(NULL)
        , _row(row)
        , _col(col)
        , _invalid(invalid)
    {
        for (size_t i = 0; i < row; i++)
        {
            for (size_t j = 0; j < col; j++)
            {
                if (a[i*col + j] != invalid)//此时数据为有效值
                {
                    _a.push_back(Triple<T>(i, j, a[i*col + j]));
                }
            }
        }
    };
    void Disply()
    {
        size_t index = 0;
        for (size_t i = 0; i < _row; i++)
        {
            for (size_t j = 0; j < _col; j++)
            {
                if (index < _a.size() && _a[index]._r == i&&_a[index]._c == j)
                {
                    cout << _a[index]._value << " ";
                    index++;
                }
                else
                {
                    cout << _invalid << " ";
                }
            }
            cout << endl;
        }
        cout << endl;
    }
protected:
    vector < Triple<T>> _a;//有效值
    size_t _row;
    size_t _col;
    T _invalid;//非法值
};

void TestSparseMatrix()
{
    int array[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 } };

    SparseMatrix<int> s1((int*)array, 6, 5, 0);
    s1.Disply();
}

这里写图片描述

三.矩阵的转置
将原矩阵的行、列对换,也就是将[i][j]和[j][i]位置上的数据对换。

这里写图片描述

代码测试:

//转置矩阵
template <typename T>
struct Triple//三元组  
{
    Triple(size_t r = 0, size_t c = 0, T value = T())
        :_r(r)
        , _c(c)
        , _value(value)
    {}

    size_t _r;
    size_t _c;
    T _value;
};

template <typename T>
class SparseMatrix
{
public:
    SparseMatrix()
        :_a(NULL)
        , _row(0)
        , _col(0)
        , _invalid(T())
    {}
    SparseMatrix(T* arr, size_t row, size_t col, const T& invalid)
        :_a(NULL)
        , _row(row)
        , _col(col)
        , _invalid(invalid)
    {
        size_t index = 0;
        for (size_t i = 0; i < row; i++)
        {
            for (size_t j = 0; j < col; j++)
            {
                if (arr[i*col + j] != invalid)//此时为有效数据
                {
                    _a.push_back(Triple<T>(i, j, arr[i*col + j]));
                }
            }
        }
    }
    void Disply()
    {
        size_t index = 0;
        for (size_t i = 0; i < _row; i++)
        {
            for (size_t j = 0; j < _col; j++)
            {
                if (index < _a.size()
                    && _a[index]._r == i
                    && _a[index]._c == j)
                {
                    cout << _a[index]._value << " ";
                    index++;
                }
                else
                {
                    cout << _invalid << " ";
                }
            }
            cout << endl;
        }
        cout << endl;
    }
    SparseMatrix<T> Transport()
    {
        SparseMatrix<T> st;
        st._row = _col;
        st._col = _row;
        st._a.reserve(_a.size());
        for (size_t i = 0; i < _col; ++i)
        {
            size_t index = 0;
            while (index < _a.size())
            {
                if (_a[index]._c == i)
                {
                    Triple<T> tmp(_a[index]._c, _a[index]._r, _a[index]._value);
                    st._a.push_back(tmp);
                }
                ++index;
            }
        }
        return st;
protected:
    vector<Triple<T>> _a;
    size_t _row;//行  
    size_t _col;//列  
    T _invalid;//无效值  
};

void TestSparseMatrix()
{
    int array[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 } };

    SparseMatrix<int> s1((int*)array, 6, 5, 0);
    s1.Disply();

    SparseMatrix<int> s2;
    s2 = s1.Transport();
    s2.Disply();
}

这里写图片描述

四.矩阵的快速转置

这里写图片描述

RowCounts{2,0,2,0,2} //统计转置后矩阵每一行的有效个数
RowStart{0,2,2,4,4} //统计转置后矩阵每一行在压缩矩阵中存储的开始位置

1.算法:
a.统计出转置之后的矩阵每一行有效值的个数count,并将有效数据直接定位到新三元组的对应位置处,此时的时间复杂度为O(2*有效值的个数+N)
b.用count统计新矩阵每一行的有效值的个数统计即原来矩阵的每一列的有效值的个数,通过遍历原来的三元组,将原来三元组的列下标作为count的下标,只要原来三元组的列存在有效值该count的对应下标就+1.
c.start找到新矩阵的每一行的第一个元素在新三元组的存储下标.进行下一步
d.再次遍历原来的三元组,将该数据直接放入新三元组对应的下标处,此时将start位置的存储数据+1,防止插入到相同的位置覆盖以前存放的数据

2.代码测试

template <typename T>
struct Triple//三元组  
{
    Triple(size_t r = 0, size_t c = 0, T value = T())
        :_r(r)
        , _c(c)
        , _value(value)
    {}

    size_t _r;
    size_t _c;
    T _value;
};

template <typename T>
class SparseMatrix
{
public:
    SparseMatrix()
        :_a(NULL)
        , _row(0)
        , _col(0)
        , _invalid(T())
    {}
    SparseMatrix(T* arr, size_t row, size_t col, const T& invalid)
        :_a(NULL)
        , _row(row)
        , _col(col)
        , _invalid(invalid)
    {
        size_t index = 0;
        for (size_t i = 0; i < row; i++)
        {
            for (size_t j = 0; j < col; j++)
            {
                if (arr[i*col + j] != invalid)//此时为有效数据
                {
                    _a.push_back(Triple<T>(i, j, arr[i*col + j]));
                }
            }
        }
    }
    void Disply()
    {
        size_t index = 0;
        for (size_t i = 0; i < _row; i++)
        {
            for (size_t j = 0; j < _col; j++)
            {
                if (index < _a.size()
                    && _a[index]._r == i
                    && _a[index]._c == j)
                {
                    cout << _a[index]._value << " ";
                    index++;
                }
                else
                {
                    cout << _invalid << " ";
                }
            }
            cout << endl;
        }
        cout << endl;
    }

    SparseMatrix<T> FastTransport()//快速转置矩阵
    {
        SparseMatrix<T> fast;
        fast._row = _col;
        fast._col = _row;
        fast._a.resize(_a.size());
        int *count = new int[_col];
        memset(count, 0, sizeof(int)* _col);
        for (size_t i = 0; i < _a.size(); ++i)
        {
            int col1 = _a[i]._c;
            ++count[col1];
        }
        int *start = new int[_col];
        memset(start, 0, sizeof(int)* _col);

        size_t i = 0;
        start[i] = 0;
        for (i = 1; i < _col; i++)
        {
            start[i] = start[i - 1] + count[i - 1];
        }
        for (size_t i = 0; i < _a.size(); i++)
        {
            int col2 = _a[i]._c;
            size_t tmp = start[col2];
            fast._a[tmp]._r = _a[i]._c;
            fast._a[tmp]._c = _a[i]._r;
            fast._a[tmp]._value = _a[i]._value;
            ++start[col2];
        }
        delete[]start;
        delete[]count;
        return fast;
    }

protected:
    vector<Triple<T>> _a;
    size_t _row;//行  
    size_t _col;//列  
    T _invalid;//无效值  
};

void TestSparseMatrix()
{
    int array[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 } };

    SparseMatrix<int> s1((int*)array, 6, 5, 0);
    s1.Disply();

    SparseMatrix<int> s3;
    s3 = s1.FastTransport();
    s3.Disply();
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值