三元组矩阵的乘法


三元组矩阵的乘法,针对稀疏矩阵:

源代码如下:

<构造位置表用了两种方法>

#include <stdlib.h>
#include <stdio.h>
#define MAXSIZE 100	//非零元的最大个数
#define MAX_ROW_NUM 20//最大行列数
#define ElenType int
#define Status int//返回值类型
#define OK 1
#define ERROR 0
#define OVERFLOW -1

/*稀疏矩阵的三元组存储结构*/
typedef struct {
	int row,col;//非零元的行下标和列下标
	ElenType data;//元素的值
}Triple;
typedef struct {
	Triple dataArray[MAXSIZE+1];//非零元组表,dataArray[0]未用
	int rpos[MAX_ROW_NUM+1];//各行第一个非零元的位置(在目标矩阵中的存储位置)表
	int row_count,col_count,data_count;//矩阵的行数,列数和非零元个数
}*TSMatrix,Matrix;//代表Triple Sequence Matrix 三元组矩阵

/*创建一个矩阵*/
Status CreateTSMatrix(TSMatrix &M){
	M = (TSMatrix)malloc(sizeof(Matrix));
	if(!M){
		exit(OVERFLOW);
	}
	printf("输入三元组的行数,列数和非零元个数:");
	int rc,cc,dc;
	scanf("%d%d%d",&rc,&cc,&dc);
	M->row_count = rc;
	M->col_count = cc;
	M->data_count = dc;
	int i = 0;
	printf("开始构造矩阵\n");
	int r,c,d;//作为临时变量
	while(i<dc){
		printf("输入第%d个非零元的行号,列号和值:",i+1);
		scanf("%d%d%d",&r,&c,&d);
		if(r>rc || c>cc){	//行和列不能越界
			printf("此组数据不合法,请重新输入\n");
			continue;
		}else{
			//因为下标从1 开始,所以i+1
			M->dataArray[i+1].row = r;
			M->dataArray[i+1].col = c;
			M->dataArray[i+1].data = d;
			i++;//此时才++
		}
	}
	/*构造rpos[]的值*/
	//////////方法一//////////
	/*此方法就是只用一个数组rpos本身来构造*/
	for(i=1;i<=M->row_count;i++){
		M->rpos[i] = 0;//赋初值为0
	}
	for(i=1;i<=M->data_count;i++){
		M->rpos[M->dataArray[i].row]++;//计算每一行有多少个非零元
	}
	//从后往前计算rpos[]的值,即累加
	for(i=M->row_count;i>=1;i--){
		M->rpos[i] = 1;
		for(int j=i-1;j>=1;j--){
			M->rpos[i] += M->rpos[j];
		}
	}
	/////////方法二//////////
	/*用一个辅助数组num来计算非零元个数,与稀疏矩阵的转置里方法一致*/
/*	int i=1,num[MAX_ROW_NUM+1];
	for(i=1;i<=M->row_count;i++){
		M->rpos[i] = 0;//赋初值为0
	}
	for(i=1;i<=M->data_count;i++){
		num[M->dataArray[i].row]++;//计算每一行有多少个非零元
	}
	M->rpos[1] = 1;
	for(i=2;i<=M->row_count;i++){
		M->rpos[i] = M->rpos[i-1] + num[i];//递推
	}
*/
	printf("构造矩阵成功\n");
	return OK;
}
/*打印三元组矩阵*/
Status PrintTSMatrix(TSMatrix M){
	//用描述法吧
	for(int i=1;i<=M->data_count;i++){
		printf("行号 列号 值:%d %d %d",M->dataArray[i].row,M->dataArray[i].col, M->dataArray[i].data);
		printf("\n");
	}
	return OK;
}
/*实现矩阵的乘法: Q = M * N */
Status MultTSMatrix(TSMatrix M,TSMatrix N,TSMatrix &Q){
	int arow,brow,p,q,ccol,ctemp[MAX_ROW_NUM+1],t,tp;
	if(M->col_count != N->row_count){//不能相乘
		return ERROR;
	}
	if(0 == M->data_count * N->data_count ){//有一个是零矩阵
		return ERROR;
	}
	//Q初始化
	Q->row_count = M->row_count;
	Q->col_count = N->col_count;
	Q->data_count = 0;
	//从M的第一行开始到最后一行,arow是M的当前行
	for(arow=1;arow<=M->row_count;arow++){
		for(ccol=1;ccol<=Q->col_count;ccol++){
			ctemp[ccol] = 0;//Q的当前行的各列元素清零
		}
		Q->rpos[arow] = Q->data_count + 1;//开始时从第一个存储位置开始存,后面是基于前面的
		if(arow < M->row_count){
			tp = M->rpos[arow+1];//下一行的起始位置
		}else{
			tp = M->data_count + 1;//最后一行的边界
		}
		for(p=M->rpos[arow];p<tp;p++){
			//对M当前行的每一个非零元
			//找到对应元素在N中的行号,即M中当前元的列号
			brow = M->dataArray[p].col;
			//原理同上
			if(brow<N->row_count){
				t = N->rpos[brow+1];
			}else{
				t = N->data_count+1;
			}
			for(q=N->rpos[brow];q<t;q++){
				ccol = N->dataArray[q].col;//乘积元素在Q中列的位置
				ctemp[ccol] += M->dataArray[p].data * N->dataArray[q].data;
			}//for_q
		}//for_p
		//该压缩存储该行非零元了
		for(ccol=1;ccol<=Q->col_count;ccol++){
			if(0!=ctemp[ccol]){
				if(++Q->data_count > MAXSIZE){//注意这里有个++
					return ERROR;
				}
				Q->dataArray[Q->data_count].row = arow;
				Q->dataArray[Q->data_count].col = ccol;
				Q->dataArray[Q->data_count].data = ctemp[ccol];
			}
		}
	}//for_arow
	return OK;
}
int main(){
	TSMatrix M,N,Q;
	Q = (TSMatrix)malloc(sizeof(TSMatrix));
	CreateTSMatrix(M);
	printf("矩阵M:\n");
	PrintTSMatrix(M);
	CreateTSMatrix(N);
	printf("矩阵N:\n");
	PrintTSMatrix(N);
	MultTSMatrix(M,N,Q);
	printf("矩阵Q:\n");
	PrintTSMatrix(Q);
	return 0;
}


现在用一个例子来验证一下:


运行结果:



### 稀疏矩阵乘法三元组表示 在计算机科学领域,稀疏矩阵是一种大部分元素为零的矩阵。对于这种类型的矩阵,存储和计算效率可以通过仅保存非零元素及其位置的方式显著提高。一种常见的方法是使用 **三元组表示法** (Triplet Representation),其中每个非零元素由其行索引、列索引以及对应的值组成。 #### 三元组表示法的核心概念 三元组表示法通常通过一个二维数组来记录稀疏矩阵中的非零元素。每一行代表一个非零元素的信息,具体形式如下: | 行号 | 列号 | 值 | |------|------|----| | i | j | v | 这里 `i` 和 `j` 是该非零元素所在的行列编号,而 `v` 是对应的实际数值[^1]。 当两个稀疏矩阵 A 和 B 进行相乘时,可以利用它们各自的三元组表示来进行高效运算。以下是实现这一过程的关键步骤解析: #### 实现稀疏矩阵乘法的具体逻辑 假设我们有两个稀疏矩阵 \(A\) 和 \(B\) 的三元组表示分别为 \(\text{triplet}_A\) 和 \(\text{triplet}_B\)。要得到结果矩阵 \(C = AB\),需遵循以下原则: 1. 遍历矩阵 \(A\) 中的所有非零元素 (\(a_{ij}\)) 并找到与其匹配的矩阵 \(B\) 中的非零元素 (\(b_{jk}\))。 2. 如果存在相同的中间维度下标 \(j\),则累加相应的乘积到结果矩阵 \(C\) 对应的位置上。 此过程中需要注意的是如何快速定位可能存在的共同项。这一步骤可通过预处理排序或者哈希表辅助完成以提升性能。 下面给出基于 Python 编程语言的一个简单示例代码片段展示上述算法思路: ```python def sparse_matrix_multiply(triplet_A, triplet_B, rows_A, cols_B): result_triplets = [] # 构建字典用于加速查找操作 dict_B = {} for row_b in triplet_B: key = (row_b[0], row_b[1]) if key not in dict_B: dict_B[key] = [] dict_B[key].append(row_b) # 执行实际的乘法并收集有效条目 for elem_a in triplet_A: i, k, val_a = elem_a if (k,) in {key[:1] for key in dict_B}: matches = [(l,m,val) for l,m,val in dict_B.get((k,), [])] for _, m, val_b in matches: new_val = val_a * val_b found = False for idx,res_elem in enumerate(result_triplets): ri,rj,_ = res_elem if ri==i and rj==m: result_triplets[idx][2]+=new_val found=True break if not found: result_triplets.append([i,m,new_val]) return sorted(result_triplets),rows_A,cols_B # Example Usage triplet_A = [[0, 0, 3], [0, 2, 7]] triplet_B = [[0, 0, 5], [2, 1, 8]] result_triplets, n_rows_C, n_cols_C = sparse_matrix_multiply( triplet_A, triplet_B, len(set([item[0] for item in triplet_A])), max(item[1]+1 for item in triplet_B)) print(f"Resultant Sparse Matrix Triplets:\n{result_triplets}") ``` 以上代码展示了如何采用三元组方式执行两稀疏矩阵间的乘法,并返回新的三元组列表作为最终输出的一部分[^2]。 #### 性能考量与优化建议 尽管上述基本框架能够满足大多数需求场景下的功能实现,但在面对大规模数据集时仍可能存在瓶颈。因此,在工程实践中可考虑引入更多高级技术手段进一步改进效率,比如但不限于: - 使用更高效的内部结构代替原始列表(如 NumPy 数组); - 应用多线程或多进程机制充分利用现代硬件资源; - 探讨 GPU 加速方案针对特定应用场合提供额外支持等[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值