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

稀疏矩阵:矩阵中大多数元素为0的矩阵(本文以行序为主序)

稀疏矩阵的三元组表述法:

        wKioL1cLsP7QRQIfAAAHqmH0VZY633.png

类型结构:

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_t row, size_t col, const T& invalid);
	~SparseMatrix();
	void Display()const;
	SparseMatrix<T> Transport()const;
	SparseMatrix<T> FastTransport()const;
protected:
	vector<Triple<T>> _array;
	size_t _rowCount;
	size_t _colCount;
	T _invalid;
};

代码实现压缩存储:

//稀疏矩阵
template <typename T>
SparseMatrix<T>::SparseMatrix(){}
template <typename T>
SparseMatrix<T>::SparseMatrix(const T* array, size_t row, size_t col, const T& invalid)
:_rowCount(row), _colCount(col), _invalid(invalid)
{
	assert(array);
	for (size_t i = 0; i < row; ++i)
	{
		for (size_t j = 0; j < col; ++j)
		{
			if (array[i*col + j] != invalid)
			{
				this->_array.push_back({ i, j, array[i*col + j] });
			}
		}
	}
}
template <typename T>
SparseMatrix<T>::~SparseMatrix()
{}
template <typename T>
void SparseMatrix<T>::Display()const
{
	size_t size = this->_array.size();
	size_t iCount = 0;
	for (size_t i = 0; i < this->_rowCount; ++i)
	{
		for (size_t j = 0; j < this->_colCount; ++j)
		{
			if (iCount < size && i == this->_array[iCount]._row && j == this->_array[iCount]._col)
			{
				cout << this->_array[iCount]._value << " ";
				++iCount;
			}
			else
			{
				cout << this->_invalid << " ";
			}
		}
		cout << endl;
	}
}

稀疏矩阵的转置:

1)列序递增转置法:找出第i行全部元素:从头到尾扫描三元组表A,找出其中所有_col==i的三元组,转置后放入三元组表B中。代码实现如下:

template <typename T>
SparseMatrix<T> SparseMatrix<T>::Transport()const
{
	SparseMatrix<T> ret;
	ret._rowCount = this->_colCount;
	ret._colCount = this->_rowCount;
	ret._invalid = this->_invalid;
	size_t size = this->_array.size();
	for (size_t col = 0; col < this->_colCount; ++col)
	{
		for (size_t iCount = 0; iCount < size; ++iCount)
		{
			if (this->_array[iCount]._col == col)
			{
				ret._array.push_back({ this->_array[iCount]._col, this->_array[iCount]._row, 
									this->_array[iCount]._value });
			}
		}
	}
	return ret;
}

2)一次定位快速转置法

在方法1中为了使转置后矩阵的三元组表B仍按行序递增存放,必须多次扫描被转置的矩阵的三元组表A。为了能将被转置三元组表A的元素一次定位到三元组B的正确位置上,需要预先计算以下数据:

    i)待转置矩阵三元组表A每一列中非0元素的总个数,即转置后矩阵三元组元素B的每一行的非0元素总个数

    ii)待转置矩阵每一列中第一个非0元素在三元组表B中的正确位置,即转置后矩阵每一行中第一个非0元素在三元组B中的正确位置

    为此,需要设两个数组分别为num[] 和 pos[] ,其中num[col]用来存放三元组表A第col列中非0元素元素总个数,pos[col]用来存放转置前三元组表A中第col列中第一个非0元素在三元组表B中的存储位置。

num[col]的计算方法:将三元组表A扫描一遍,对于其中列号为col的元素,给相应的num数组中下标为col的元素加1.

pos[col]的计算方法:

    i)pos[0] = 0,表示三元组表A中,列值为0的第一个非0元素在三元组表B中的下标值。

    ii)pos[col] = pos[col - 1] + num[col - 1],其中1<=col<A.size();

eg:

0  1  9  0  0  0  0

0  0  0  0  0  0  0

3  0  0  0  0  4  0

0  0  2  0  0  0  0

0  8  0  0  0  0  0

 5  0  0  7  0  0  0 

col0123456
num[col]2221010
pos[col]0246778

代码实现:

template <typename T>
SparseMatrix<T> SparseMatrix<T>::Transport()const
{
	SparseMatrix<T> ret;
	ret._rowCount = this->_colCount;
	ret._colCount = this->_rowCount;
	ret._invalid = this->_invalid;
	size_t size = this->_array.size();
	for (size_t col = 0; col < this->_colCount; ++col)
	{
		for (size_t iCount = 0; iCount < size; ++iCount)
		{
			if (this->_array[iCount]._col == col)
			{
				ret._array.push_back({ this->_array[iCount]._col, this->_array[iCount]._row, 
									this->_array[iCount]._value });
			}
		}
	}
	return ret;
}
template <typename T>
SparseMatrix<T> SparseMatrix<T>::FastTransport()const
{
	SparseMatrix<T> ret;
	ret._rowCount = this->_colCount;
	ret._colCount = this->_rowCount;
	ret._invalid = this->_invalid;
	size_t size = this->_array.size();	
	ret._array.resize(size);
	vector<int> num(this->_colCount);
	vector<int> pos(this->_colCount); //pos[i] = pos[i-1]+num[i-1] i>0
	for (size_t i = 0; i < size; ++i)
	{
		++num[this->_array[i]._col];
	}
	for (size_t col = 1; col < this->_colCount; ++col)
	{
		pos[col] = pos[col - 1] + num[col - 1];
	}
	for (size_t i = 0; i < size; ++i)
	{
		ret._array[pos[this->_array[i]._col]++] = { this->_array[i]._col, this->_array[i]._row, this->_array[i]._value };
	}

	return ret;
}

运行结果:

wKiom1cLvL2gXwaYAAA58epvyB0736.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
稀疏矩阵压缩存储方式是一种常用的优化存储方式,可以有效节省存储空间。在这种存储方式,矩阵的非零元素被存储为一个三元组 (i, j, value) 的形式,其 i 和 j 分别表示该元素在矩阵的行坐标和列坐标,value 表示该元素的值。 转置是指将矩阵的行和列交换,即行变为列,列变为行。在稀疏矩阵压缩存储方式转置需要重新生成一个新的三元组数组来存储转置后的矩阵。 以下是稀疏矩阵压缩存储转置算法的详细解释。 1. 定义一个三元组结构体来存储稀疏矩阵的三元组信息: ``` typedef struct { int row; // 行坐标 int col; // 列坐标 int value; // 元素值 } Triple; ``` 2. 定义一个稀疏矩阵结构体来存储稀疏矩阵的基本信息,包括矩阵的行数、列数、非零元素个数和三元组数组: ``` typedef struct { int rows; // 矩阵的行数 int cols; // 矩阵的列数 int nnz; // 矩阵的非零元素个数 Triple *triples; // 矩阵的三元组数组 } SparseMatrix; ``` 3. 定义一个稀疏矩阵转置的函数,该函数接受一个稀疏矩阵为参数,并返回转置后的稀疏矩阵: ``` SparseMatrix transpose(SparseMatrix A) { SparseMatrix B; B.rows = A.cols; B.cols = A.rows; B.nnz = A.nnz; B.triples = (Triple *)malloc(B.nnz * sizeof(Triple)); int *rowCounts = (int *)calloc(A.cols, sizeof(int)); for (int i = 0; i < A.nnz; i++) { rowCounts[A.triples[i].col]++; } int *rowOffsets = (int *)calloc(A.cols + 1, sizeof(int)); rowOffsets[0] = 0; for (int i = 1; i <= A.cols; i++) { rowOffsets[i] = rowOffsets[i - 1] + rowCounts[i - 1]; } for (int i = 0; i < A.nnz; i++) { int j = A.triples[i].col; int index = rowOffsets[j]; B.triples[index].row = A.triples[i].col; B.triples[index].col = A.triples[i].row; B.triples[index].value = A.triples[i].value; rowOffsets[j]++; } free(rowCounts); free(rowOffsets); return B; } ``` 4. 在转置函数,首先定义一个新的稀疏矩阵 B,该矩阵的行数等于 A 的列数,列数等于 A 的行数,非零元素个数等于 A 的非零元素个数。 5. 然后,定义两个辅助数组 rowCounts 和 rowOffsets,用于计算转置后的矩阵的三元组数组的索引。 6. 对于 rowCounts 数组,它的长度为 A 的列数,每个元素表示该列的非零元素个数。遍历 A 的三元组数组,在 rowCounts 数组对应的列上加 1。 7. 对于 rowOffsets 数组,它的长度为 A 的列数加 1,每个元素表示转置后的矩阵的三元组数组该列的起始索引。遍历 rowCounts 数组,累计计算 rowOffsets 数组每个元素的值。 8. 遍历 A 的三元组数组,根据 rowOffsets 数组的值,将转置后的三元组存储到 B 的三元组数组。 9. 最后,释放 rowCounts 和 rowOffsets 数组,并返回转置后的稀疏矩阵 B。 以上就是稀疏矩阵压缩存储转置算法的详细解释。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值