【数据结构】稀疏矩阵的压缩存储和转置算法(C++代码)

一 稀疏矩阵的定义

矩阵是如今很多科学与工程计算问题中常用的数学对象,矩阵涉及到的计算通常会出现矩阵的阶数比较高但是非零元素的个数却比较少的情况,因此,我们需要有一种方法来压缩这种比较稀疏的矩阵。

那么,首先第一个问题就是如何定义一个矩阵是否是稀疏的?参考严蔚敏的数据结构教材,第96页给出了稀疏矩阵的定义:假设在m×n的矩阵中,有t个元素不为零,令δ=t/(m+n),称δ为矩阵的稀疏因子。通常认为δ<=0.05时称为稀疏矩阵。


二 矩阵的压缩存储

那么,如何进行稀疏矩阵的压缩存储呢?

按照压缩存储的概念,只要存储矩阵中的非零元素的信息就好了,同时还需要保证根据存储的信息能唯一的确定一个矩阵。因此,采用三元祖(行,列,元素值)再加上矩阵的行、列值就可以解决这个问题。由三元组的不同表示方法可引出稀疏矩阵不同的压缩存储方法,比如说有:三元组顺序表、行逻辑链接的顺序表、十字链表等。本文暂时只讨论三元组顺序表的情况。

三元组顺序表的存储表示如下:

#define MAXSIZE 12500
typedef struct {
	int		i,j;	//元素的行下标和列下标
	ElemType	e;	//元素值
}Triple;
typedef struct{
	Triple	data[MAXSIZE+1];	//非零元素的三元组
	int	mu,nu,tu;		//矩阵的行数、列数和非零元个数
}TSMatrix;

三 矩阵的转置算法

矩阵的转置运算是一种最简单的矩阵运算,接下来介绍在稀疏矩阵存储为三元组形式下的两种矩阵转置算法。先从第一种简单的转置算法说起,并配上伪代码,文章末尾附上可运行的C++代码,后续会加附Java代码。

要获取一个矩阵的转置矩阵,我们先来分析一下初始矩阵和转置后矩阵的三元组的差异,这里假设矩阵以行序为主序进行存储,如下图所示。

                                        

a要变成b只需要经过3步:(1)将矩阵的行列值相互交换;(2)将每个三元组中的i,j相互调换;(3)重组三元组之间的次序。前两条是很容易做到的,关键是如何实现第三条。

(1)这里提出第一种解决办法,即引出了第一个算法:按照b.data中三元组的次序来找a.data中对应的三元组进行转置。也就是按照初始矩阵的列序来进行转置操作,文字描述可能会产生歧义,看下面这张图就能明白了。


伪代码如下:

Status TransposeSMatrix(TSMatrix M, TSMatrix &T){
	T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
	if(T.tu){
		q = 1;
		for (col = 1; col <= M.nu; ++col)
		{
			for (p = 1; p <= M.tu; ++p)
				if (M.data[p].j == col)
				{
					T.data[q].i = M.data[p].j;
					T.data[q].j = M.data[p].i;
					T.data[q].e = M.data[p].e;
					++q;
				}
			
		}
		return Ok;
	}
}//TransposeSMatrix

(2)还有另外一种解决办法,就是按照a.data中元素的顺序进行转置,对于每一个a.data中的元素,去找在b.data中存放的位置,这种解决办法的难点就在于如何找到a.data中元素对应于b.data中的位置。为了确定这些位置,在转置之前先做一个预处理,先求得初始矩阵中每一列的非零元素个数,进而求出每一列的第一个非零元素在b.data中的位置,这些是可以预先计算出来的。因此,需要附加num和cpot两个向量,num[col]表示矩阵中第col列中非零元素的个数,cpot[col]表示矩阵中第col列的第一个非零元素在b.data中的恰当位置,有以下公式:


伪代码如下:

Status FastTransposeSMatrix(TSMatrix M, TSMatrix &T){
	T.mu = M.nu; T.nu = M.mu; T.tu = M.tu;
	if(T.tu){
		for (col = 1; col <= M.nu; ++col) num[col] = 0;
		for (t = 1; t <= M.nu; ++t) ++num[M.data[t].j];
		cpot[1] = 1;
		for(col = 2; col <= M.nu; ++col) cpot[col] = cpot[col-1]+num[col-1];
		for (p = 1; p <= M.nu; ++p)
		{
			col = M.data[p].j;
			q = cpot[col];
			T.data[q].i = M.data[p].j;
			T.data[q].j = M.data[p].i;
			T.data[q].e = M.data[p].e;
			++cpot[col];
		}
	}
	return Ok;
}//TransposeSMatrix

附C++源码:

#include<iostream>  
#include <vector>
using namespace std;  

#define MAXSIZE 1000

typedef struct{
	int row, col; //元素所在行,列
	int elem;     //元素值
}Triple;

typedef struct {
	Triple data[MAXSIZE+1];
	int row_num, col_num, elem_num;  //矩阵的行数,列数,非零元个数
}TSMatrix;

/************************************************************************/
/*        转置算法1,时间复杂度为O(col_num*elem_num)                     */
/************************************************************************/
void TransposeMatrix(TSMatrix matrix, TSMatrix &transed_matrix){
	transed_matrix.row_num = matrix.col_num;
	transed_matrix.col_num = matrix.row_num;
	transed_matrix.elem_num = matrix.elem_num;
	int q = 0;
	//按照matrix中列的顺序来遍历matrix
	for (int i = 0; i < matrix.col_num; i++)
	{
		//找到第i列中所有的非零元素,然后加入到transed_matrix中
		for(int j = 0; j < matrix.elem_num; j++){
			//这里要减一是因为输入的时候按照下标为1开始,存储的时候是从0开始
			if((matrix.data[j].col -1) == i){
				transed_matrix.data[q].row = matrix.data[j].col;
				transed_matrix.data[q].col = matrix.data[j].row;
				transed_matrix.data[q].elem = matrix.data[j].elem;
				q++;
			}
		}
	}
}//TransposeMatrix

/************************************************************************/
/*        转置算法2,时间复杂度为O(elem_num)                             */
/************************************************************************/
void FastTransposeMatrix(TSMatrix matrix, TSMatrix &transed_matrix){

	transed_matrix.row_num = matrix.col_num;
	transed_matrix.col_num = matrix.row_num;
	transed_matrix.elem_num = matrix.elem_num;

	//添加num和cpot两个变量;
	//num[col] :  表示矩阵中第col列中非零元素的个数
	//cpot[col] : 矩阵中第col列的第一个非零元素在transed_matrix.data中的恰当位置

	/*--------初始化这两个数组---------------*/
	vector<int> num;
	num.resize(matrix.col_num, 0);
	for (int i = 0; i < matrix.elem_num; i++)
	{
		num[matrix.data[i].col-1]++;
	}
	vector<int> cpot;
	cpot.resize(matrix.col_num, 0);
	cpot[0] = 0;
	for (int col = 1; col < matrix.col_num; col++)
	{
		cpot[col] = cpot[col-1]+num[col-1];
	}
	/*--------------------------------------*/

	for (int p = 0; p < matrix.elem_num; p++)
	{
		int col = matrix.data[p].col-1;
		int q = cpot[col];
		transed_matrix.data[q].row = matrix.data[p].col;
		transed_matrix.data[q].col = matrix.data[p].row;
		transed_matrix.data[q].elem = matrix.data[p].elem;
		++cpot[col];
	}
}//FastTransposeMatrix

//打印矩阵
void printMatrix(TSMatrix matrix){
	int max_row = 0, max_col = 0;
	//获取矩阵非零元素的最大行数和最大列数
	for (int i = 0; i < matrix.elem_num; i++)
	{
		if (max_row < matrix.data[i].row)
		{
			max_row = matrix.data[i].row;
		}
		if (max_col < matrix.data[i].col)
		{
			max_col = matrix.data[i].col;
		}
	}
	//构造一个二维数组,存的是二维矩阵的元素,只是为了方便输出
	vector<vector<int>> tmp_data;
	//先初始化这个二维数组
	tmp_data.resize(max_row);
	for (int i = 0; i < max_row; i++)
	{
		tmp_data[i].resize(max_col, 0);
	}
	//将三元组中的信息添加到二维数组中
	for (int i = 0; i < matrix.elem_num; i++)
	{
		Triple tri;
		tri.col = matrix.data[i].col - 1;
		tri.row = matrix.data[i].row - 1;
		tri.elem = matrix.data[i].elem;
		tmp_data[tri.row][tri.col] = tri.elem;
	}
	for (int i = 0; i < max_row; i++)
	{
		for (int j = 0; j < max_col; j++)
		{
			cout<<tmp_data[i][j]<<"\t";
		}
		cout<<endl;
	}
	cout<<endl;
}//printMatrix

/************************************************************************/
/*                  author by bo  2017-4-6                              */
/************************************************************************/
void main(){
	TSMatrix matrix;
	TSMatrix transed_matrix;
	
	// 依次输入矩阵的非零元素个数、矩阵的行数、矩阵的列数、三元组的内容                                                                     
	cout<<"input the non-zero number of matrix:";
	cin>>matrix.elem_num;
	cout<<"input the number of row:";
	cin>>matrix.row_num;
	cout<<"input the number of column:";
	cin>>matrix.col_num;
	cout<<"input the triple of matrix(下标从1开始):"<<endl;

	for (int i = 0; i < matrix.elem_num; i++)
	{
		cin>>matrix.data[i].row>>matrix.data[i].col>>matrix.data[i].elem;
	}
	cout<<"input finished!"<<endl;

	//矩阵的转置算法1
	TransposeMatrix(matrix, transed_matrix);
	//矩阵的转置算法2
//	FastTransposeMatrix(matrix, transed_matrix);

	cout<<"/--------原始矩阵------------\\"<<endl;
	printMatrix(matrix);
	cout<<"\\----------------------------/"<<endl;

	cout<<"/--------转置后矩阵-----------\\"<<endl;
	printMatrix(transed_matrix);
	cout<<"\\----------------------------/"<<endl;
}//main



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值