稀疏矩阵的转置

稀疏矩阵-----矩阵中有效元素的个数远远小于总元素的个数。所以,要是我们把矩阵中

所有元素都存储起来的话,这样子对空间就是造成极大的浪费。所以,我们采用压缩

储,即就是,将有效元素存储在一个三元组中(包括元素所在行,列,值),这样就

减少了空间的浪费。

三元组定义如下:

template<typename T>
struct Triple
{
	T _value;
	size_t _row;
	size_t _col;
	Triple(T value = 0,size_t row = 0,size_t col = 0)
		:_value(value)
		,_row(row)
		,_col(col)
	{}
};


我们知道,矩阵的转置就是交换元素的行和列。下边图解:


由于上述的转置方法效率比较低下,所以,我们采用另一种方法:见图


下边给出实现代码:

//声明:代码中的几处注释,仅仅是个人心得
#pragma once
#include<iostream>
using namespace std;
#include<vector>

template<typename T>
struct Triple
{
	T _value;
	size_t _row;
	size_t _col;
	Triple(T value = 0,size_t row = 0,size_t col = 0)
		:_value(value)
		,_row(row)
		,_col(col)
	{}
};

template<typename T>
class SparseMatrix
{
public:
	typedef Triple<T> Triple;
	SparseMatrix()
	{}
	SparseMatrix(T* a, size_t m, size_t n, const T& invalid)
		:_rowSize(m)
		, _colSize(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)
				{
					_a.push_back(Triple(a[i * n + j], i, j));
				}
				else
				{
					continue;
				}
			}
		}
	}

	void Display()
	{
		size_t index = 0;
		for (size_t i = 0; i < _rowSize; ++i)
		{
			for (size_t j = 0; j < _colSize; ++j)
			{
				size_t size = _a.size();
				/*if ((_a[index]._row == i)
					&& (_a[index]._col == j)//注意:三个条件顺序不同,下边的实现则不同
					&& (index < size))*/  //如果这样写,下边的加一操作必须进行条件判断
				if ((index < size)
					&&(_a[index]._row == i)
					&& (_a[index]._col == j))//最好写成这样
				{
					cout << _a[index]._value << " ";
					//if (index != size - 1)
						++index;
				
				}
				else
				{
					cout << _invalid << " ";
				}
			}
			cout << endl;
		}
		cout << endl;
	}
	SparseMatrix<T> Transport()
	{
		SparseMatrix<T> sm;
		sm._colSize = _rowSize;
		sm._rowSize = _colSize;
		sm._invalid = _invalid;
		sm._a.reserve(_a.size());
		
		for (size_t i = 0; i < _colSize; ++i)
		{
			size_t index = 0;
			while (index < _a.size())
			{
				if (_a[index]._col == i)
				{
					sm._a.push_back(Triple(_a[index]._value, _a[index]._col, _a[index]._row));
				}
				++index;
			}
		}

		return sm;
	}
	SparseMatrix<T> FastTransport()
	{
		SparseMatrix<T> sm;
		sm._colSize = _rowSize;
		sm._rowSize = _colSize;
		sm._invalid = _invalid;
		sm._a.resize(_a.size());

		//nums数组的初始化
		int* nums = new int[_colSize];
		memset(nums,0,sizeof(int)*_colSize);
		for (size_t index = 0; index < _a.size(); ++index)
		{
			int col = _a[index]._col;
			++nums[col];
		}

		//start数组初始化
		int* start = new int[_colSize];
		start[0] = 0;

		for (size_t i = 1; i < _colSize; ++i)
		{
			start[i] = start[i - 1] + nums[i - 1];
		}

		//转置
		for (size_t i = 0; i < _a.size(); ++i)
		{
			int col = _a[i]._col;
			int begin = start[col];

			sm._a[begin]._row = _a[i]._col;
			sm._a[begin]._col = _a[i]._row;
			sm._a[begin]._value = _a[i]._value;
			++ start[col];
		}

		delete[] nums;
		delete[] start;
		return sm;
	}
private:
	vector<Triple> _a;//存放结构体的容器
	size_t _rowSize;
	size_t _colSize;
	T _invalid;
};
void TestSparseMatrix()
{
	int a[5][6] = {
		{0,1,0,3,0,5},
		{0,0,0,0,0,0},
		{0,2,0,4,0,6},
		{0,0,0,0,0,0},
		{ 0,0,0,0,0,0 }
	};
	SparseMatrix<int> sp((int*)a,5,6,0);
	sp.Display();
	SparseMatrix<int> tsm = sp.Transport();
	tsm.Display();
	SparseMatrix<int> ftsm = sp.FastTransport();
	ftsm.Display();
}


上边这段程序的完成过程中,也是遇到了各种各样的问题,原因还是对STL容器使用不

熟练,比如resize()和reserve()的区别;

resize()改变size为指定的值,而reserve()改变容量(size并没有改变)。

Transport函数中我们用的是reserve(),(其实sm._a.reserve(_a.size())不要也行),

竟我们是向容器中push数据。如果使用resize(),后有什么后果。resize()不仅仅是改

大小,还会将这块空间置为随机值,所以之后push(可以push进去,vector

自动改变量),新的内容会被写入resize那段空间之后,在display时,输出的矩阵

的元素全是0(无效值)。

FastTransport函数中,我们必须使用resize,因为我们后边使用的是[]操作([pos]必须

保证pos要小于当前size)。但是也有人说,不使用resize,然后后边使用push_back,

其实,我尝试过这样的办法,快速转置是将原矩阵的有效元素放到新矩阵的对应位置,

push_back只能做到放到新矩阵,但是不能保证放到正确的位置。所以,我们必须使用

resize().


以上说法如有问题,请回复~~不甚感激

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值