稀疏矩阵的三元组表示----(算法详解)

目录

基本算法包括:(解释都在代码里)

1.创建

2.对三元组元素赋值

3.将三元组元素赋值给变量

4.输出三元组

5.转置(附加的有兴趣可以看看)


稀疏矩阵的概念:矩阵的非零元素相较零元素非常小时,这个矩阵就叫稀疏矩阵。

稀疏矩阵可以用三元组表示十字链表表示

本文章介绍三元组表示

稀疏矩阵的三元组表示。

三元组表示就是,用三个变量来存储非零元素的信息。

三元组线性表按顺序存储结构存储。

三元组顺序表的数据类型声明如下:

#include <stdio.h>
#define M 6
#define N 7
#define MaxSize  100         //矩阵中非零元素最多个数
typedef int ElemType;
typedef struct
{
	int r;					//行号
	int c;					//列号
	ElemType d;				//元素值
} TupNode;					//三元组定义
typedef struct 
{	
	int rows;				//行数
	int cols;				//列数
	int nums;				//非零元素个数
	TupNode data[MaxSize];
} TSMatrix;					//三元组顺序表

基本算法包括:(解释都在代码里)

1.创建

2.对三元组元素赋值

3.将三元组元素赋值给变量

4.输出三元组

5.转置(附加的有兴趣可以看看)

1.创建:

void CreatMat(TSMatrix &t,ElemType A[M][N])  //从一个二维稀疏矩阵创建其三元组表示
{
	int i,j;
	t.rows=M;t.cols=N;t.nums=0;
	for (i=0;i<M;i++)
	{
		for (j=0;j<N;j++) 
			if (A[i][j]!=0) 	//只存储非零元素
			{
				t.data[t.nums].r=i;t.data[t.nums].c=j;
				t.data[t.nums].d=A[i][j];t.nums++;
			}
	}
}

2.对三元组元素赋值

先找行后找列

bool Value(TSMatrix &t,ElemType x,int i,int j)  //三元组元素赋值
{
	int k=0,k1;
	if (i>=t.rows || j>=t.cols)
		return false;				//失败时返回false
	while (k<t.nums && i>t.data[k].r) k++;					//查找行
	while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列
	if (t.data[k].r==i && t.data[k].c==j)	//存在这样的元素
		t.data[k].d=x;
	else									//不存在这样的元素时插入一个元素
	{	
		for (k1=t.nums-1;k1>=k;k1--)
		{
			t.data[k1+1].r=t.data[k1].r;
			t.data[k1+1].c=t.data[k1].c;
			t.data[k1+1].d=t.data[k1].d;
		}
		t.data[k].r=i;t.data[k].c=j;t.data[k].d=x;
		t.nums++;
	}
	return true;						//成功时返回true
}

3.将三元组元素赋值给变量

bool Assign(TSMatrix t,ElemType &x,int i,int j)  //将指定位置的元素值赋给变量
{
	int k=0;
	if (i>=t.rows || j>=t.cols)
		return false;			//失败时返回false
	while (k<t.nums && i>t.data[k].r) k++;					//查找行
	while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列
	if (t.data[k].r==i && t.data[k].c==j)
		x=t.data[k].d;
	else
		x=0;				//在三元组中没有找到表示是零元素
	return true;			//成功时返回true
}

4.输出三元组

void DispMat(TSMatrix t)		//输出三元组
{
	int i;
	if (t.nums<=0)			//没有非零元素时返回
		return;
	printf("\t%d\t%d\t%d\n",t.rows,t.cols,t.nums);
	printf("\t------------------\n");
	for (i=0;i<t.nums;i++)
		printf("\t%d\t%d\t%d\n",t.data[i].r,t.data[i].c,t.data[i].d);
}

5.转置(附加的有兴趣可以看看)

void TranTat(TSMatrix t,TSMatrix &tb)		//矩阵转置
{
	int p,q=0,v;					//q为tb.data的下标
	tb.rows=t.cols;tb.cols=t.rows;tb.nums=t.nums;
	if (t.nums!=0)					//当存在非零元素时执行转置
	{
		for (v=0;v<t.cols;v++)		//tb.data[q]中的记录以c域的次序排列
			for (p=0;p<t.nums;p++)	//p为t.data的下标
				if (t.data[p].c==v)
				{
					tb.data[q].r=t.data[p].c;
					tb.data[q].c=t.data[p].r;
					tb.data[q].d=t.data[p].d;
					q++;
				}
	}
}

总代码: c++

//稀疏矩阵的三元组表示-算法
#include <stdio.h>
#define M 6
#define N 7
#define MaxSize  100         //矩阵中非零元素最多个数
typedef int ElemType;
typedef struct
{
	int r;					//行号
	int c;					//列号
	ElemType d;				//元素值
} TupNode;					//三元组定义
typedef struct 
{	
	int rows;				//行数
	int cols;				//列数
	int nums;				//非零元素个数
	TupNode data[MaxSize];
} TSMatrix;					//三元组顺序表

void CreatMat(TSMatrix &t,ElemType A[M][N])  //从一个二维稀疏矩阵创建其三元组表示
{
	int i,j;
	t.rows=M;t.cols=N;t.nums=0;
	for (i=0;i<M;i++)
	{
		for (j=0;j<N;j++) 
			if (A[i][j]!=0) 	//只存储非零元素
			{
				t.data[t.nums].r=i;t.data[t.nums].c=j;
				t.data[t.nums].d=A[i][j];t.nums++;
			}
	}
}
bool Value(TSMatrix &t,ElemType x,int i,int j)  //三元组元素赋值
{
	int k=0,k1;
	if (i>=t.rows || j>=t.cols)
		return false;				//失败时返回false
	while (k<t.nums && i>t.data[k].r) k++;					//查找行
	while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列
	if (t.data[k].r==i && t.data[k].c==j)	//存在这样的元素
		t.data[k].d=x;
	else									//不存在这样的元素时插入一个元素
	{	
		for (k1=t.nums-1;k1>=k;k1--)
		{
			t.data[k1+1].r=t.data[k1].r;
			t.data[k1+1].c=t.data[k1].c;
			t.data[k1+1].d=t.data[k1].d;
		}
		t.data[k].r=i;t.data[k].c=j;t.data[k].d=x;
		t.nums++;
	}
	return true;						//成功时返回true
}

bool Assign(TSMatrix t,ElemType &x,int i,int j)  //将指定位置的元素值赋给变量
{
	int k=0;
	if (i>=t.rows || j>=t.cols)
		return false;			//失败时返回false
	while (k<t.nums && i>t.data[k].r) k++;					//查找行
	while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列
	if (t.data[k].r==i && t.data[k].c==j)
		x=t.data[k].d;
	else
		x=0;				//在三元组中没有找到表示是零元素
	return true;			//成功时返回true
}
void DispMat(TSMatrix t)		//输出三元组
{
	int i;
	if (t.nums<=0)			//没有非零元素时返回
		return;
	printf("\t%d\t%d\t%d\n",t.rows,t.cols,t.nums);
	printf("\t------------------\n");
	for (i=0;i<t.nums;i++)
		printf("\t%d\t%d\t%d\n",t.data[i].r,t.data[i].c,t.data[i].d);
}
void TranTat(TSMatrix t,TSMatrix &tb)		//矩阵转置
{
	int p,q=0,v;					//q为tb.data的下标
	tb.rows=t.cols;tb.cols=t.rows;tb.nums=t.nums;
	if (t.nums!=0)					//当存在非零元素时执行转置
	{
		for (v=0;v<t.cols;v++)		//tb.data[q]中的记录以c域的次序排列
			for (p=0;p<t.nums;p++)	//p为t.data的下标
				if (t.data[p].c==v)
				{
					tb.data[q].r=t.data[p].c;
					tb.data[q].c=t.data[p].r;
					tb.data[q].d=t.data[p].d;
					q++;
				}
	}
}
int main()
{
	TSMatrix t,tb;
	int x,y=10;
	int A[6][7]={
		{0,0,1,0,0,0,0},
		{0,2,0,0,0,0,0},
		{3,0,0,0,0,0,0},
		{0,0,0,5,0,0,0},
		{0,0,0,0,6,0,0},
		{0,0,0,0,0,7,4}};
	CreatMat(t,A);
	//printf("b:\n"); DispMat(t);
	//if (Assign(t,x,2,5)==true)  //调用时返回true
	//	printf("Assign(t,x,2,5)=>x=%d\n",x);
	//else  //调用时返回false
	//	printf("Assign(t,x,2,5)=>参数错误\n");
	//Value(t,y,2,5);
	//printf("执行Value(t,10,2,5)\n");
	//if (Assign(t,x,2,5)==true)  //调用时返回true
	//	printf("Assign(t,x,2,5)=>x=%d\n",x);
	//else  //调用时返回false
	//	printf("Assign(t,x,2,5)=>参数错误\n");
	//printf("b:\n"); DispMat(t);
	TranTat(t,tb);
	printf("tb:\n"); DispMat(tb);
	return 1;
}

c总代码(需要自取)

#define  _CRT_SECURE_NO_WARNINGS 1
#include <stdbool.h>
#include <stdio.h>
#include <string.h> 
#include <stdlib.h>
//三元组表示
typedef int ElemType;
#define MaxSize 100
#define M 6
#define N 7
typedef struct Tup
{
	int r;
	int c;
	ElemType d;
}TupNode;
typedef struct TS
{
	int rows;
	int cols;
	int nums;
	TupNode data[MaxSize];
}TsMatrix;
void CreateMat(TsMatrix* t, ElemType A[M][N])
{
	int i, j;
	t->rows = M; t->cols = N; t->nums = 0;
	for(i = 0;i<M;i++)
		for(j=0;j<N;j++)
			if (A[i][j] != 0)
			{
				t->data[t->nums].r = i; t->data[t->nums].c = j; t->data[t->nums].d = A[i][j]; t->nums++;
			}
}
bool Value(TsMatrix* t, ElemType x, int i, int j)
{
	if (i >= t->rows || j >= t->cols) return false;
	int k = 0;
	while (k<t->rows && i>t->data[k].r) k++;
	while (k<t->cols && i == t->data[k].r && j>t->data[k].c) k++;
	if (i == t->data[k].r && j == t->data[k].c) t->data[k].d = x;
	else {
		for (int k1 = t->nums - 1; k1 >= k; k1--)
		{
			t->data[k1 + 1].r = t->data[k1].r;
			t->data[k1 + 1].c = t->data[k1].c;
			t->data[k1 + 1].d = t->data[k1].d;
		}
		t->data[k].r = i; t->data[k].c = j; t->data[k].d = x;
		t->nums++;
	}
	return true;
}
void DispMat(TsMatrix* t)
{
	if (t->nums <= 0) return;
	printf("\t%d\t%d\t%d\n", t->rows, t->cols, t->nums);
	printf("\t--------------------------\n");
	for (int k = 0; k < t->nums; k++)
		printf("\t%d\t%d\t%d\n", t->data[k].r, t->data[k].c, t->data[k].d);
}
bool Assign(TsMatrix* t, ElemType* x, int i, int j)
{
	if (i >= t->rows || j >= t->cols) return false;
	int k = 0;
	while (k < t->nums && i>t->data[k].r) k++;
	while (k<t->nums && i == t->data[k].r && j>t->data[k].c)k++;
	if (t->data[k].r == i && t->data[k].c == j) *x = t->data[k].d;
	else x = 0;
	return true;
}
void TranTat(TsMatrix* t, TsMatrix* b)
{
	if (t->nums != 0)
	{
		b->rows = t->cols; b->cols = t->rows;
		b->nums = t->nums;
		int k1 = 0;
		for(int v = 0;v<t->cols;v++)
			for (int k = 0; k < t->nums; k++)
			{
				if (t->data[k].c == v)
				{
					b->data[k1].r = t->data[k].c;
					b->data[k1].c = t->data[k].r;
					b->data[k1].d = t->data[k].d;
					k1++;
				}
			}
	}

}

int main()
{
	ElemType A[6][7] = {
		{0,0,1,0,0,0,0},
		{0,2,0,0,0,0,0},
		{3,0,0,0,0,0,0},
		{0,0,0,5,0,0,0},
		{0,0,0,0,6,0,0},
		{0,0,0,0,0,7,4} };
	TsMatrix* t = (TsMatrix*)malloc(sizeof(TsMatrix));
	CreateMat(t, A);
	//Value(t, 7, 0, 4);
	ElemType e = 0;
	TsMatrix* b = (TsMatrix*)malloc(sizeof(TsMatrix));
	TranTat(t, b);
	/*Assign(t, &e, 1, 1);
	printf("%d", e);*/
	DispMat(b);
	return 0;
}

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固自己的知识点,和一个学习的总结,对文章有任何问题的还请指出,接受大家的批评,让我改进,如果大家有所收获的话还请不要吝啬你们的点赞和收藏,这可以激励我写出更加优秀的文章。

  • 31
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
稀疏矩阵是指其中大部分元素为零的矩阵。由于大多数矩阵都是稠密的,即大多数元素都不为零,因此通常情况下,我们使用一个二维数组来表示一个矩阵。但是,对于稀疏矩阵来说,这种方法会造成很大的浪费,因为大量的空间被用来存储零元素。为了解决这个问题,我们可以使用稀疏矩阵三元组表示法。 稀疏矩阵三元组表示法是将稀疏矩阵中每个非零元素的和值存储在一个三元组中。其数据结构如下所示: ``` struct Triple{ int row, col; double value; }; ``` 其中,row表示非零元素所在的,col表示非零元素所在的,value表示非零元素的值。我们可以使用一个数组来存储所有的非零元素,这个数组就是稀疏矩阵三元组稀疏矩阵三元组表示法的优点是它可以节省存储空间,缺点是它不方便进矩阵运算。因此,在进矩阵运算时,我们需要将稀疏矩阵转换成其他更方便进矩阵运算的表示方法,如压缩矩阵和坐标矩阵等。 对于稀疏矩阵的求解,可以使用稀疏矩阵三元组表示法结合三元组高斯消元算法来进求解。三元组高斯消元算法是一种针对稀疏矩阵的高斯消元算法,其基本思想是将矩阵化为上三角矩阵或下三角矩阵,然后通过回代或者前代求解方程。由于矩阵中大部分元素为零,因此在进高斯消元时,我们只需要考虑非零元素,这样可以大大提高计算效率。 三元组高斯消元算法的基本步骤如下: 1. 将稀疏矩阵转换成三元组表示法; 2. 对三元组按照的顺序进排序; 3. 从第一个非零元素开始,进高斯消元,将矩阵化为上三角矩阵或下三角矩阵; 4. 通过回代或者前代求解方程。 具体实现可以参考以下代码: ``` void SparseTripletGaussElimination(SparseTriplet& triplet, vector<double>& b) { int n = triplet.rows; vector<Triple> A(triplet.data, triplet.data + triplet.num); sort(A.begin(), A.end(), [](const Triple& a, const Triple& b){ return a.row < b.row || (a.row == b.row && a.col < b.col); }); vector<int> row(n+1), col(triplet.num), diag(n); vector<double> val(triplet.num); for (int i = 0; i < triplet.num; i++) { row[A[i].row]++; } for (int i = 1; i <= n; i++) { row[i] += row[i-1]; } for (int i = 0; i < triplet.num; i++) { int r = A[i].row, c = A[i].col; double v = A[i].value; int k = row[r]++; // 获取 r 中下一个非零元素的位置 col[k] = c; val[k] = v; if (r == c) { diag[r] = k; // 记录对角线元素的位置 } } for (int k = 0; k < n-1; k++) { if (val[diag[k]] == 0) { // 对角线元素为零,无法消元 throw runtime_error("zero pivot encountered"); } for (int i = diag[k]+1; i < row[k+1]; i++) { int r = col[i]; double factor = val[i] / val[diag[k]]; for (int j = diag[k]+1; j < row[k+1]; j++) { if (col[j] == r) { val[j] -= factor * val[diag[k]]; } } b[r] -= factor * b[k]; } } if (val[diag[n-1]] == 0) { // 对角线元素为零,无法消元 throw runtime_error("zero pivot encountered"); } for (int k = n-1; k >= 0; k--) { double sum = 0; for (int i = diag[k]+1; i < row[k+1]; i++) { sum += val[i] * b[col[i]]; } b[k] = (b[k] - sum) / val[diag[k]]; } } ``` 其中,SparseTriplet是稀疏矩阵三元组表示法的数据结构,b是待求解的方程的右侧向量。在实现中,我们首先将三元组按照的顺序进排序,然后将其转换成压缩矩阵的形式,接着进高斯消元,并通过回代或者前代求解方程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值