介绍两种矩阵,以及这两种矩阵压缩存储

并且使用C++实现它们

矩阵可以看为二维数组,存储与访问就和二维数组一样。


1.对称矩阵,如下图形式

对称存储架构 对称矩阵存储容量_数据结构

此矩阵可以看为a[5][5]的二维数组行下标用i表示,列下标用j表示

很显然除对称轴以外的数据存储时同一个数据会存两遍,如果将相同的数存一遍,在矩阵很大的情况下就会节省很多的存储空间。

压缩存储数据就是只存储以对称轴分开的上三角或下三角的数据

对称存储架构 对称矩阵存储容量_矩阵_02

也就是原来存N*N个数据,现在只存N*(N+1)/2个数据

对称矩阵中,只存了下三角的数据,下三角中有个特点就是i>=j,在访问上三角数据时,就可以转换为访问下三角数据

就是i和j交换。在访问某一特定的数据时,就可以利用二维数组的存储方式,得出:i*(i+1)/2+j

代码实现:

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

template<class T>
class SymmetricMatrix
{
public:
	SymmetricMatrix(int *a,size_t N)//带参构造函数
		:_N(N)
	{
		_matrix = 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)
				{
					_matrix[index] = a[i*N + j];
					++index;
				}
				else
					break;
			}
		}
	}
	~SymmetricMatrix()//析构函数
	{
		delete[] _matrix;
		_matrix = 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;
		}
	}

	const T& Access(size_t i, size_t j) const//上三角元素转下三角
	{
		if (i < j)
			swap(i, j);
		return _matrix[i*(i + 1) / 2 + j];
	}
protected:
	T* _matrix;//压缩存储的一维数组
	size_t _N;//N*N的矩阵
};

void SymmetricMatrixTest()//测试用例
{
	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);

	sm.Display();
}

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




2.稀疏矩阵

稀疏矩阵的特点就是,一个矩阵里有效数据远小于无效数据,且没有规则。如:

对称存储架构 对称矩阵存储容量_c++_03

稀疏矩阵的压缩:使用{row,col,value}三元组存储每一个有效 数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放。

存放后就是:

对称存储架构 对称矩阵存储容量_压缩_04

矩阵的转置:就是行列对换,上面的矩阵经过转置后就变为:

对称存储架构 对称矩阵存储容量_压缩_05

转置后三元组的行优先,就可以转换成转置前的列优先。

转置还有一种更快的方式,就是快速转置。

快速转置就是对转置的优化,提高了时间复杂度,快速转置引入了两个变量记录每个有效的位置,直接进行存储,只遍历一次三元组的存储。

代码如下:

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

template <class T>
struct Triple//三元组
{
	size_t _row;//行
	size_t _col;//列
	T _value;//有效值

	Triple(size_t row, size_t col, const T& value)//带参构造函数
		:_row(row)
		, _col(col)
		, _value(value)
	{}

	Triple()//无参构造函数
	{}
};

template <class T>
class SparseMatrix//稀疏矩阵
{
public:
	SparseMatrix(T *a, size_t M, size_t N, const T& invalid = T())//带参构造函数
		:_M(M)
		, _N(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> t(i, j, a[i*N + j]);
					_matrix.push_back(t);//调用vector插入有效数据
				}
			}
		}
	}

	SparseMatrix()//无参构造函数
	{}

	void Display()//打印矩阵
	{
		size_t index = 0;
		for (size_t i = 0; i < _M; ++i)
		{
			for (size_t j = 0; j < _N; ++j)
			{
				if (index < _matrix.size() && _matrix[index]._row == i && _matrix[index]._col == j)//有效数据
				{
					cout << _matrix[index]._value << " ";
					++index;
				}
				else//无效数据
				{
					cout << _invalid << " ";
				}
			}
			cout << endl;
		}
		cout << endl;
	}

	SparseMatrix<T> Transport()//转置
	{
		SparseMatrix<T> sm;
		sm._M = _N;
		sm._N = _M;
		sm._invalid = _invalid;
		sm._matrix.reserve(_matrix.size());
		for (size_t i = 0; i < _N; ++i)
		{
			for (size_t index = 0; index < _matrix.size(); ++index)
			{
				if (_matrix[index]._col == i)
				{
					Triple<T> t( _matrix[index]._col, _matrix[index]._row,_matrix[index]._value);
					/*Triple<T> t(_matrix[index]);
					swap(t._col, t._row);*/
					sm._matrix.push_back(t);
				}
			}
		}
		return sm;
	}

	SparseMatrix<T> FastTransport()//快速转置
	{
		SparseMatrix<T> sm;
		sm._M = _N;
		sm._N = _M;
		sm._invalid = _invalid;
		sm._matrix.resize(_matrix.size());

		int* count = new int[_N];
		memset(count, 0, sizeof(int)*_N);
		int* start = new int[_N];

		for (size_t index = 0; index < _matrix.size(); ++index)
		{
			count[_matrix[index]._col]++;
		}
		start[0] = 0;
		for (size_t i = 1; i < _N; ++i)
		{
			start[i] = start[i - 1] + count[i - 1];
		}

		for (size_t index = 0; index < _matrix.size(); ++index)
		{
			int row = _matrix[index]._col;
			/*Triple<T> t(_matrix[index]);
			swap(t._col, t._row);*/
			Triple<T> t(_matrix[index]._col, _matrix[index]._row, _matrix[index]._value);
			sm._matrix[start[row]] = t;
			start[row] ++;
		}
		return sm;
	}

protected:
	vector<Triple <T>> _matrix;
	size_t _M;
	size_t _N;
	T _invalid;
};

void SparseMatrixTest()
{
	int a[6][5] =
	{
		{ 1, 0, 0, 0, 5 },
		{ 0, 3, 0, 4, 0 },
		{ 0, 0, 0, 0, 0 },
		{ 2, 0, 0, 0, 6 },
		{ 0, 0, 1, 0, 0 },
		{ 0, 0, 0, 0, 0 },
	};
	SparseMatrix<int> sm((int*)a, 6, 5, 0);//稀疏矩阵
	sm.Display();

	SparseMatrix<int> ret = sm.Transport();//转置矩阵
	ret.Display();

	SparseMatrix<int> ret1 = sm.FastTransport();//快速转置矩阵
	ret1.Display();
}
int main()
{
	SparseMatrixTest();
	return 0;
}