矩阵的压缩存储以及转置

来源:互联网 发布:杨紫 否认整容 知乎 编辑:程序博客网 时间:2024/06/03 12:31

一.对称矩阵的压缩存储

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.对称矩阵例子:

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

4.代码实现

//对称矩阵的压缩存储template<class T>class SymmetricMatrix{public:SymmetricMatrix(T* a, size_t N)//将矩阵存放到下三角中:_N(N){for (size_t i = 0; i < _N; ++i){for (size_t j = 0; j < _N; ++j){if (i >= j){_a.push_back(a[i*_N + j]);}elsebreak;}}}T& Access(size_t i, size_t j)//打印矩阵的任意位置{if (i < j)swap(i, j);return _a[i*(i + 1) / 2 + j];}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)<<" ";elsecout << Access(j, i)<<" ";}cout << endl;}}protected:vector<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);cout << s.Access(3, 1) << endl;cout << s.Access(1, 3) << endl;s.Display();}

二.稀疏矩阵的压缩存储

1.什么样的矩阵为稀疏矩阵?

      一个M行N列(即M*N)的矩阵,矩阵中有效值得个数远小于无效值的个数,且这些数据的

分布没有规律。

2.稀疏矩阵的压缩存储?

        压缩存储值存储极少数的有效数据。使用{row,col,value}三元组存储每一个有效数据,三元组按原矩阵中

的位置,以行优先级先后顺序依次存放。

3.稀疏矩阵的例子:

一个六行五列的稀疏矩阵(M=6,N=5)

1   0   3   0   5   0

0   0   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   0   0   0

4.代码实现:

//稀疏矩阵的压缩存储template<class T>struct Triple  //三元组存放有效数据的值以及行列值{T _value;size_t _row;size_t _col;};template<class T,size_t M,size_t N>class SparseMatrix{public:SparseMatrix(T a[M][N], const T& invalid) //将有效值压入三元组:_invalid(invalid){for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if (a[i][j] != _invalid){Triple<T> t;t._value = a[i][j];t._row = i;t._col = j;_a.push_back(t);}}}}T& Access(size_t i ,size_t j){size_t index = 0;while (index < _a.size()){if (_a[index]._row == i&&_a[index]._col == j){return _a[index]._value;}++index;}return _invalid;}void Display(){size_t index = 0;for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if ((index < _a.size()) && (_a[index]._row == i)&&(_a[index]._col == j)){cout << _a[index]._value << " ";++index;}else{cout << _invalid << " ";}}cout << endl;}cout << endl;}protected:vector<Triple<T>> _a;T _invalid;};void TestSparseMatrix(){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(array,0);cout << sm.Access(3, 0) << endl;cout << sm.Access(3, 1) << endl;sm.Display();}


三.稀疏矩阵的转置

1.普通转置:

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

例如:


算法思想

       三元组里边存放数据是按行优先存储的,矩阵的转置也就是将原矩阵的行、列互换,原矩阵是M行N列的,

那么转置后的矩阵是N行M列的,用一个for循环遍历原矩阵的每一列,然后和三元组里边的每一列相比较,如果

列相等就将原矩阵三元组里边的这个有效数据的值以及行列值,存放到转置后的三元组里边

代码实现:

//矩阵的转置template<class T>struct Triple  //三元组存放有效数据的值以及行列值{T _value;size_t _row;size_t _col;};template<class T,size_t M,size_t N>class SparseMatrix{friend SparseMatrix<T, N, M>;public:SparseMatrix():_a(NULL), _invalid(T()){}SparseMatrix(T a[M][N], const T& invalid) //将有效值压入三元组:_invalid(invalid){for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if (a[i][j] != _invalid){Triple<T> t;t._value = a[i][j];t._row = i;t._col = j;_a.push_back(t);}}}}SparseMatrix<T, N, M> Transport() //矩阵的转置{SparseMatrix<T, N, M> tsm;tsm._a.reserve(_a.size());for (size_t i = 0; i < N; i++)//转置前的每一列是转置后的每一行{size_t index = 0;while (index < _a.size()){if (_a[index]._col == i){Triple<T> t;t._col = _a[index]._row;t._row = _a[index]._col;t._value = _a[index]._value;tsm._a.push_back(t);}++index;}}return tsm;}void Display(){size_t index = 0;for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if ((index < _a.size()) && (_a[index]._row == i)&&(_a[index]._col == j)){cout << _a[index]._value << " ";++index;}else{cout << _invalid << " ";}}cout << endl;}cout << endl;}protected:vector<Triple<T>> _a;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,6,5> sm(array,0);sm.Display();SparseMatrix<int, 5, 6> tsm;tsm = sm.Transport();tsm.Display();}


  由于矩阵的转置时间复杂度为o(有效数据的个数*原矩阵的N列)

  时间复杂度高所以引入了快速转置

2.矩阵的快速转置:

算法思想:


实现代码 :

//矩阵的快速转置template<class T>struct Triple  //三元组存放有效数据的值以及行列值{T _value;size_t _row;size_t _col;};template<class T,size_t M,size_t N>class SparseMatrix{friend SparseMatrix<T, N, M>;public:SparseMatrix():_a(NULL), _invalid(T()){}SparseMatrix(T a[M][N], const T& invalid) //将有效值压入三元组:_invalid(invalid){for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if (a[i][j] != _invalid){Triple<T> t;t._value = a[i][j];t._row = i;t._col = j;_a.push_back(t);}}}}SparseMatrix<T, N, M> FastTransport()//矩阵的快速转置{SparseMatrix<T, N, M>tsm;int rows[N] = { 0 };size_t index = 0;//转置后每一行的数据个数while (index < _a.size()){rows[_a[index]._col]++;++index;}//转置后每一行的每一个数的起始位置int starts[N] = { 0 };starts[0] = 0;for (size_t i = 1; i < N; ++i){starts[i] = starts[i - 1] + rows[i - 1];}index = 0;tsm._a.resize(_a.size());//开辟有效数据个数的空间while (index < _a.size()){size_t row = _a[index]._col;Triple<T> t;t._value = _a[index]._value;t._col = _a[index]._row;t._row = _a[index]._col;tsm._a[starts[row]++] = t;++index;}return tsm;}void Display(){size_t index = 0;for (size_t i = 0; i < M; ++i){for (size_t j = 0; j < N; ++j){if ((index < _a.size()) && (_a[index]._row == i)&&(_a[index]._col == j)){cout << _a[index]._value << " ";++index;}else{cout << _invalid << " ";}}cout << endl;}cout << endl;}protected:vector<Triple<T>> _a;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,6,5> sm(array,0);sm.Display();SparseMatrix<int, 5, 6> tsm;tsm = sm.FastTransport();tsm.Display();}



0 0
原创粉丝点击