对称矩阵、稀疏矩阵

本文介绍了一种用于高效存储稀疏矩阵和对称矩阵的C++模板类实现。通过对矩阵进行压缩存储,可以显著减少内存占用并提高运算效率。文章详细展示了如何通过三元组来表示稀疏矩阵,并提供了两种转置方法:普通转置和快速转置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#pragma once

#include <vector>

// 对称矩阵存储
template<class T>
class SymmetricMatrix
{
public:
	SymmetricMatrix(T* a, size_t size)
		:_a(new T[size*(size+1)/2])
		,_size(size*(size+1)/2)
	{
		assert(a);

		size_t index = 0;
		for (size_t i = 0; i < size; ++i)
		{
			for (size_t j = 0; j < size; ++j)
			{
				if (i >= j)
				{
					_a[index++] = a[i*size+j]; 
				}
				else
				{
					break;
				}
			}
		}
	}

	T& Access(size_t i, size_t j)
	{
		if (i < j)
		{
			swap(i, j);
		}

		return _a[i*(i+1)/2+j];
	}

protected:
	T* _a;
	size_t _size;
};

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> sm((int*)a, 5);
}

// 三元组
template<class T>
struct Trituple
{
	int _row;	// 行
	int _col;	// 列
	T	_value; // 数据

	Trituple(int row = 0, int col = 0, const T& value = 0)
		:_row(row)
		,_col(col)
		,_value(value)
	{}
};

//
// 稀疏矩阵
// 定长的静态存储
// 动态存储
//
template<class T>
class SparseMatrix
{
public:
	SparseMatrix(T* ar = 0, int row = 0, int col = 0, const T& invalid = 0)
		:_rowSize(row)
		,_colSize(col)
		,_invalid(invalid)
	{
		for(int i = 0; i < row; ++i)
		{
			for (int j = 0; j < col; ++j)
			{
				if (ar[i * col + j] != invalid)
				{
					_matrixs.push_back(Trituple<T>(i, j, ar[i * col + j]));
				}
			}
		}
	}

	~SparseMatrix()
	{}

	void Display()
	{
		size_t index = 0;
		for (int i = 0; i < _rowSize; ++i)
		{
			for (int j = 0; j < _colSize; ++j)
			{
				if (index < _matrixs.size()
					&& _matrixs[index]._row == i && _matrixs[index]._col == j)
				{
					cout<<" "<<_matrixs[index]._value;
					++index;
				}
				else
				{
					cout<<" "<<_invalid;
				}
			}

			cout<<endl;
		}

		cout<<endl;
	}

	// 矩阵转置
	SparseMatrix<T> Transpose()
	{
		SparseMatrix<T> sm;

		sm._rowSize = _colSize;
		sm._colSize = _rowSize;
		sm._invalid = _invalid;

		for (int i = 0; i < _colSize; ++i)
		{
			size_t index = 0;
			while (index < _matrixs.size()) 
			{
				if (_matrixs[index]._col == i)
				{
					sm._matrixs.push_back(Trituple<T>());
					sm._matrixs.back()._row = i;
					sm._matrixs.back()._col = _matrixs[index]._row;
					sm._matrixs.back()._value = _matrixs[index]._value;
				}

				++index;
			}
		}

		return sm;
	}

	// 矩阵转置
	SparseMatrix<T> FastTranspose()
	{
		SparseMatrix<T> sm;

		sm._rowSize = _colSize;
		sm._colSize = _rowSize;
		sm._invalid = _invalid;

		for (size_t i = 0; i < _matrixs.size(); ++i)
		{
			sm._matrixs.push_back(Trituple<T>());
		}

		int* rowCounts = new int[_colSize];
		int* rowStart = new int[_colSize];
		memset(rowCounts, 0, sizeof(int)*_colSize);
		memset(rowStart, 0, sizeof(int)*_colSize);

		// 统计转置后矩阵每一行的数据个数
		for (size_t i = 0; i < _matrixs.size(); ++i)
		{
			rowCounts[_matrixs[i]._col]++;
		}

		// 统计转置后的矩阵每行在压缩矩阵中存储的开始位置
		rowStart[0] = 0;
		for (int i = 1; i < _colSize; ++i)
		{
			rowStart[i] = rowStart[i - 1] + rowCounts[i - 1];
		}

		for (size_t i = 0; i < _matrixs.size(); ++i)
		{
			size_t index = rowStart[_matrixs[i]._col];
			sm._matrixs[index]._col = _matrixs[i]._row;
			sm._matrixs[index]._row = _matrixs[i]._col;
			sm._matrixs[index]._value = _matrixs[i]._value;

			++(rowStart[_matrixs[i]._col]);
		}

		delete[] rowCounts;
		delete[] rowStart;

		return sm;
	}

private:
	vector<Trituple<T> > _matrixs;
	int _rowSize;	// 行
	int _colSize;	// 列
	T _invalid;		// 无效值
};

void Test1()
{
	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> sm((int*)array, 6, 5, 0);
	sm.Display();

	SparseMatrix<int> ret1 = sm.Transpose();
	ret1.Display();

	SparseMatrix<int> ret2 = sm.FastTranspose();
	ret2.Display();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值