稀疏矩阵的压缩

稀疏矩阵的特点

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

例如下面的矩阵

稀疏矩阵的压缩存储

压缩矩阵值存储极少数的有效数据。使用三元组来存储每一个数据,三元组数据按照矩阵中的位置,以行优先顺序依次存放。

则上述矩阵的存储结构为

三元组结构

//三元组的定义
template<class T>
struct  Triple
{
public:
	//默认无参构造函数
	Triple()
	{}

	//构造函数
	Triple(const T& d,size_t row=0,size_t col=0)
		:_value(d)
		,_row(row)
		,_col(col)
	{}
public:
	T _value;//数据域
	size_t _row;//行
	size_t _col;//列
};
template<class T>
class SparseMatrix
{
public:
	//无参构造函数
	SparseMatrix()
	{}
	SparseMatrix(const T* a, size_t row, size_t col, const T& invalid);
	void Display();//打印
	SparseMatrix<T> Transport();//列转置
	SparseMatrix<T> FastTransport();//快速转置

private:
	vector<Triple<T>> _a;//三元组类型的顺序表
	size_t _rowSize;//行数
	size_t _colSize;//列数
	T _invalid;//非法值
};

//矩阵的压缩
template<class T>
SparseMatrix<T>::SparseMatrix(const T* a, size_t row, size_t col, const T& invalid)
	:_rowSize(row)
	, _colSize(col)
	, _invalid(invalid)
{
	//行遍历
	for (size_t i = 0; i < row; i++)
	{
		//列遍历
		for (size_t j = 0; j < col; j++)
		{
			if (a[i*col + j] != invalid)
			{
				_a.push_back(Triple<T>(a[i*col + j], i, j));
				//不能通过数组创建,但是可以通过数组形式访问
			}
		}
	}
}

转置

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

列转置

算法思想:

采用按照被转置矩阵三元组表A的序列(即转置后三元组表B的行序)递增的顺序进行转置,并以此送入转置后矩阵的算远足表B中,这样一来,转置后矩阵的三元组表B恰好是以“行序为主序的”.

实现代码

//列转置
template<class T>
SparseMatrix<T> SparseMatrix<T>::Transport()
{
	SparseMatrix<T> result;
	//行列size互换
	result._rowSize = _colSize;
	result._colSize = _rowSize;
	result._invalid = _invalid;

	//按照列扫描
	for (size_t j = 0; j < _colSize; j++)
	{
		//在三元组数组中找到相同列的元素
		for (size_t index = 0; index < _a.size(); index++)
		{
			if (_a[index]._col == j)
			{
				result._a.push_back(Triple<T>(_a[index]._value, _a[index]._col, _a[index]._row));
				//按照列优先的顺序存到压缩数组中
			}
		}
	}
	return result;
}

算法分析:

算法的时间主要消耗在双重循环中,其时间复杂度为O(_colSize*_a.size)。

一次定位快速转置

算法思想:

在列转置中算法的时间浪费主要在双重循环中,要改善算法的性能,必须去掉双重循环,使得整个转置过程通过一次循环来完成。

为了能使得被转置的三元组表A中元素一次定位到三元组表B中,需要预先计算一下数据:

1)rowCounts,三元组表A中每一列有效值的个数,即转置后矩阵三元组表B中每一行有效值的个数。

2)rowStart,三元组表B中每一行有效值的起始位置。

rowStart[col]=rowStart[col-1]+rowCounts[col-1]

上述矩阵的两个数组为:

代码实现:

//快速转置
template<class T>
SparseMatrix<T> SparseMatrix<T>::FastTransport()
{
	assert(_a.size() < 0);
	SparseMatrix<T> result;
	//行列size互换
	result._rowSize = _colSize;
	result._colSize = _rowSize;
	result._invalid = _invalid;

	//建立rowCounts和rowStart
	int* rowCounts = new int[_colSize];
	int* rowStart = new int[_colSize];
	memset(rowCounts, 0, sizeof(int)*_colSize);//初始化为0
	memset(rowStart, 0, sizeof(int)*_colSize);//初始化为0

	result._a.resize(_a.size());//复制顺序表_a,容量相同,但是数据不同。
	//初始化
	for (size_t i = 0; i < _colSize; i++)
	{
		rowCounts[_a[i]._col]++;
	}
	rowStart[0] = 0;
	for (size_t i = 1; i < _colSize; i++)
	{
		rowStart[i] = rowCounts[i - 1] + rowStart[i - 1];
	}

	//快速转置
	size_t index = 0;
	Triple<T> tmp;
	while (index < _a.size())
	{
		int row = _a[index]._col;//行数
		int rowIndex = rowStart[row];//当前行的起始位置

									 //交换行和列
		tmp._value = _a[index]._value;
		tmp._row = _a[index]._col;
		tmp._col = _a[index]._row;

		result._a[rowIndex] = tmp;
		rowStart[row]++;
		index++;
	}
	delete[] rowCounts;
	delete[] rowStart;
	return result;

}

算法分析:

一次定位快速转置算法时间主要浪费在3个并列的循环中,分别执行了_colSize,_col_Size,_a.size()次,总的时间复杂度为O(_colSize+_a.size())。远远小于O(_colSize*_a.size)。

时间: 2024-12-05 04:43:15

稀疏矩阵的压缩的相关文章

c++稀疏矩阵的压缩存储

稀疏矩阵 M*N的矩阵 其中有效值的个数远小于无效值的个数 且分布没有规律 Eg: 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}}; 稀疏矩阵的压缩存储 压缩存储值存储极少数的有效数据.使用{row,col,value}//行 列 值三元组存储每一个有效 数据,三元组按原矩阵中的位置,以行优先级

对称矩阵、稀疏矩阵的压缩存储

1)对称矩阵的压缩存储 对称矩阵顾名思义就是符合行和列的个数相同,并且矩阵中存储的数据上三角和下三角中对应位置上的元素值是相等的.为了能够减少存储的空间,我们可以只存储上三角矩阵.或者下三角矩阵中的元素,这样就能够极大地节省空间的浪费.下面是对称矩阵的示列: 假设对称矩阵为n*n,这里以行优先存储下三角矩阵,总共需要存储的元素有n*(n+1)/2个元素,从而将n*n个元素压缩到n*(n+1)/2大小的空间中. 下面是具体的程序实现: --symmetric.h文件 //实现对称矩阵 #inclu

稀疏矩阵的压缩存储及转置

没有经过处理的稀疏矩阵其实就是一个特殊的二维数组,数组中的大部分元素是0或者其他类型的非法值,只有少数几个非零元素. 为了实现压缩存储,可以只存储稀疏矩阵的非0元素.在存储稀疏矩阵中的非0元素时,必须要存储该元素的行列号以及元素值.我们可以封装一个三元组类来存储这些元素. //三元组 template<class T> struct Triple { size_t _row;   //行 size_t _col;   //列 T _value;      //值 Triple<T>

稀疏矩阵的压缩存储和转置

1.稀疏矩阵:M*N的矩阵,矩阵中有效值的个数远小于无效值的个数,且这些数据的分布没有规律. 2.稀疏矩阵的压缩存储:压缩存储值存储极少数的有效数据. 由于非零元素分布没有任何规律,所以在进行压缩存储的时侯需要存储无效值的同时还要存储有效元素在矩阵中的位置,即有效元素所在的行号和列号,也就是在存储某个元素比如aij的值的同时,还需要存储该元素所在的行号i和它的列号j,这样就构成了一个三元组(i,j,aij)的线性表. 使用{ row, col, value }三元组存储每一个有效数据,三元组按原

C++实现稀疏矩阵的压缩存储、转置、快速转置

/*稀疏矩阵的压缩存储.转置.快速转置*/ #include <iostream> using namespace std; #include <vector> //三元组 template<class T> struct Triple { size_t _row; size_t _col; T _value; Triple(size_t row = 0, size_t col = 0, const T& value = T()) :_row(row) ,_co

【数据结构】稀疏结构及稀疏矩阵的压缩存储,矩阵的转置

在矩阵中,有一类很重要的矩阵,就是-----稀疏矩阵. 所谓的稀疏矩阵呢,就是指的是,在矩阵中,有效的数据个数远远小于无效的数据个数(并且这些数据排列顺序没有规律).我们下面先举个稀疏矩阵的例子: 有效数据个数仅仅6个,其余都为无效数据0. 那我们将稀疏矩阵存在压缩矩阵中,设定一个三元组,使用{row,col,value}存储每一个有效数据,三元组按原矩阵中的位置,以行优先级先后顺序依次存放. 我们建立一个结构体: struct Triple//定义一个三元组,用来存储稀疏矩阵的x,y,坐标值

稀疏矩阵的压缩存储及快速转置

当一个矩阵为稀疏矩阵时,有效数据的个数比无效数据要少得多,因此若将一个矩阵全部存储会浪费空间,可以只将有效数据存储起来,无效数据作为标记 代码如下: #include <iostream> #include <vector> using namespace std; //可用一个三元组来存储有效数据的信息 template<class T> struct Triple {  size_t _row;  size_t _col;  T _value; }; //系数矩阵类

对称矩阵及稀疏矩阵的压缩

对称矩阵 设一个N*N的方阵A,A中的任意元素A[i][j],当且仅当A[i][j]=A[j][i],则矩阵A是对称矩阵,以对角线分隔,分为上三角和下三角 压缩矩阵存储对称矩阵时只需要存储其上三角或者下三角的数据,即最多存储n(n+1)/2个数据,对应关于为:i>j,symmetricMatrix[i][j]=A[i*(i+1)/2+j] 代码实现: template<class T> class SymmetricMatrix { public: SymmetricMatrix(T*a

稀疏矩阵的压缩存储与转置

稀疏矩阵:矩阵中大多数元素为0的矩阵(本文以行序为主序) 稀疏矩阵的三元组表述法: 类型结构: template <typename T> struct Triple { int _row; int _col; T _value; }; template <typename T> class SparseMatrix { public: SparseMatrix<T>::SparseMatrix(); SparseMatrix(const T* array, size_