稀疏矩阵

稀疏矩阵的定义:

M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没有规律。

具体实现代码:

1、定义一个三元组

因为要分布没有规律,所以用一个三元组来保存坐标与值之间的关系

代码如下:

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

2、存储稀疏矩阵的数组

主要包括构造、打印、转置、快速转置

(1)函数声明如下:

template<class T>
class SparseMatrix
{
public:
	SparseMatrix(T* a, int m, int n, const T& invalid);//非法值
	SparseMatrix();
public:
	void Display();//打印
	SparseMatrix<T> Transport();//转置
	SparseMatrix<T>  FastTransport();//快速转置
protected:
	vector<Triple<T>> _a;
	size_t _rows;
	size_t _columns;
	T _invalid;
};

(2)构造和打印:

template<class T>
SparseMatrix<T>::SparseMatrix(T* a, int m, int n, const T& invalid)//非法值
	:_rows(m)
	, _columns(n)
	, _invalid(invalid)
{
	for (int i = 0; i < m; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			if (a[i*n + j] != invalid)
			{
				/*	Triple<T> t(i, j, a[i*n + j]);
				_a.push_back(t);*/
				//或者写成下面这样
				_a.push_back(Triple<T>(i, j, a[i*n + j]));
			}
		}
	}
}


template<class T>
SparseMatrix<T>::SparseMatrix()
	:_columns(0)
	, _rows(0)
	, _invalid(0)
{}



template<class T>
void SparseMatrix<T>::Display()//打印
{
	size_t index = 0;
	for (int i = 0; i < _rows; ++i)
	{
		for (int j = 0; j < _columns; ++j)
		{
			if (index < _a.size()
				&& _a[index]._row == i
				&&_a[index]._col == j)
			{
				cout << _a[index++]._value << " ";
			}
			else
			{
				cout << _invalid << " ";
			}
		}
		cout << endl;
	}
	cout << endl;
}

(3)转置:

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

例子:


实际上是一列一列的遍历矩阵,对应的压缩存储的数组,则是跳着分别去找对应列为1、2、3....的元素,每个列数相同的元素都找完,然后列数加1,再去遍历此列数的元素,元素是一个一个放入数组中的

代码如下:

template<class T>
SparseMatrix<T> SparseMatrix<T>::Transport()//转置
{
	SparseMatrix<T> tmp;
	tmp._invalid = _invalid;
	tmp._columns = _rows;
	tmp._rows = _columns;
	tmp._a.reserve(_a.size());
	for (size_t i = 0; i < _columns; ++i)
	{
		size_t index = 0;
		while (index < _a.size())
		{
			if (_a[index]._col == i)
			{
				Triple<T> tp;
				tp._row = _a[index]._col;
				tp._col = _a[index]._row;
				tp._value = _a[index]._value;
				tmp._a.push_back(tp);
			}
			++index;
		}
	}
	return tmp;
}

(4)快速转置:

其实是跳着插入,前面普通转置的方法每一次每一次都要去找列数相同的元素时都要去遍历一边数组,而快速转置则是遍历一边数组,每一次都找到其元素所在转置矩阵中的具体位置,但是有前提的要先事先遍历一边数组,统计出每一列元素的个数,并且计算出每一列开头元素开始的位置。然后就可以实现精确定位,不过要事先开辟好数组的空间,不能一个一个的push_back了

例子:


代码如下:

template<class T>
SparseMatrix<T> SparseMatrix<T>::FastTransport()//快速转置
{
	SparseMatrix<T> tmp;
	tmp._invalid = _invalid;
	tmp._columns = _rows;
	tmp._rows = _columns;
	//tmp._a.reserve(_a.size());
	tmp._a.resize(_a.size());
	int* rowCount = new int[_columns];
	int* rowStarts = new int[_columns];
	memset(rowCount, 0, sizeof(int)*_columns);
	memset(rowStarts, 0, sizeof(int)*_columns);		
	size_t index = 0;
	while (index < _a.size())
	{
		rowCount[_a[index]._col]++;
		index++;
	}
	rowStarts[0] = 0;
	for (size_t i = 1; i < _columns; ++i)
	{
	rowStarts[i] = rowStarts[i - 1] + rowCount[i - 1];
	}
	index = 0;
	while (index < _a.size())
	{
		int& rowStart = rowStarts[_a[index]._col];//一定要加引用,后面才可以++
		Triple<T> tp;
		tp._row = _a[index]._col;
		tp._col = _a[index]._row;
		tp._value = _a[index]._value;
		tmp._a[rowStart++] = tp;
		++index;
	}
	delete[] rowStarts;
	delete[] rowCount;
	return tmp;
}

测试用例:

void  SparseMatrixTest()
{
	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}
	};
	SparseMatrix<int> _sa((int*)a, 6, 5, 0);
	cout << endl;
	_sa.Display();
	/*SparseMatrix<int> sm1 = _sa.Transport();
	sm1.Display();*/
	SparseMatrix<int> sm2 = _sa.FastTransport();
	sm2.Display();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值