草庐IT

稀疏矩阵的加法和乘法(三元组)

想写好代码的小猫头 2024-02-13 原文

基本思路:

三元组方法:主要的特点就是最后的结果矩阵均由三元组的形式来表达,调用函数再以矩阵形式输出

(1)稀疏矩阵加法

(下图参考懒猫老师《数据结构》课程相关笔记)

 这里与普通矩阵加法不同的是,稀疏矩阵的三元组在加法计算时,如果两个矩阵中的元素相加不为0时,才调用添加元素函数添加到和矩阵三元组中(最后的和矩阵也是一个三元组)

(2)稀疏矩阵乘法

 同样,在进行稀疏矩阵的乘法运算时,计算结果矩阵的元素时,要前两个矩阵在该位置的和不为0,才调用添加元素函数添加到结果矩阵三元组

完整代码:

(稀疏矩阵(顺序).h--用来实现稀疏矩阵的基本操作和加乘功能;稀疏矩阵加乘.c--用来对稀疏矩阵的加乘操作进行验证)

(1)稀疏矩阵(顺序).h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
typedef int DataType;

typedef struct Triple {
	int row, col; //行号,列号
	DataType item;//非零元素
} Triple;

typedef struct Matrix {
	int num;//非零元素的个数
	int mu;//矩阵的行数
	int nm;//矩阵的列数
} Matrix;

void TripleMatrix(Triple *data) { //初始化
	for (int i = 0; i < MAX; i++) {
		data[i].row = -1;
		data[i].col = -1;
	}
}

void printTriple(Triple *data) { //打印三元组
	int i = 0;
	printf("生成的三元组为:(行,列,非零元素)\n");
	while (data[i].row != -1) {
		printf("(%d,%d,%d)\n", data[i].row, data[i].col, data[i].item);
		i++;
	}
}

void printfMatrix(Triple *data, Matrix *datasum) { //打印矩阵
	printf("矩阵为:\n");
	int matirx[datasum->mu][datasum->nm];
	for (int i = 0; i < datasum->mu; i++) { //先将矩阵初始化为全0阵
		for (int j = 0; j < datasum->nm; j++) {
			matirx[i][j] = 0;
		}
	}
	for (int k = 0; k < datasum->num; k++) { //将稀疏矩阵中的值赋进去
		matirx[data[k].row - 1][data[k].col  - 1] = data[k].item; //行列值记得减1
	}
	for (int i = 0; i < datasum->mu; i++) { //打印
		for (int j = 0; j < datasum->nm; j++) {
			if (j == datasum->nm - 1)
				printf("%-5d\n", matirx[i][j]);
			else
				printf("%-5d ", matirx[i][j]);
		}
	}
}

void setItem(Triple *data, int row, int col, DataType item) { //添加元素
	Triple *str = data;
	Triple temp, temp1;
	int flag = 1; //控制两种储存交替进行
	int type = 0; //控制最后一个插入的是新元素还是原来存在temp和temp1中的元素
	while (str->row != -1 || str->col != -1) {
		if (str->row > row || (str->row == row && str->col > col)) { //插在前面
			temp = *str;
			str->row = row;
			str->col = col;
			str->item = item;
			str++;
			while (str->row != -1) {
				if (flag == 1) {
					temp1 = *str;
					*str = temp; //temp准备存储下一个
					str++;
					flag = 2;
				} else if (flag == 2) {
					temp = *str;
					*str = temp1; //temp1准备存储下一个
					str++;
					flag = 1;
				}
			}
			if (flag == 1) //最后一个元素在temp中
				type = 1;
			else if (flag == 2) //最后一个元素在temp1中
				type = 2;
		} else if (str->row < row || str->row == row) {
			str++;
		}
	}
	//前面都没有添加进去,就添加到末尾
	//或者存入temp或temp1中的需要在最后添加进去
	if (type == 0) {
		str->col = col;
		str->row = row;
		str->item = item;
	} else if (type == 1) {
		*str = temp;
	} else if (type == 2) {
		*str = temp1;
	}
}

DataType getItem(Triple *data, int row, int col, Matrix *datasum) { //根据行号列号获取矩阵元素
	if (row > datasum->mu || col > datasum->nm)
		printf("该坐标不在矩阵内!\n");
	for (int i = 0; i < datasum->num; i++) {
		if (data[i].row == row && data[i].col == col)
			return data[i].item;
	}
	return 0;
}

void addMatrix(Triple *data1, Triple *data2, Matrix *datasum1, Matrix *datasum2, Triple *add,
               Matrix *addsum) {//这个传参是真的无语
	if (datasum1->mu != datasum2->mu || datasum1->nm != datasum2->nm) {//不满足加法法则
		printf("violation of calculation rules!\n");
	}
	DataType item;
	addsum->num = 0;
	addsum->mu = datasum1->mu;
	addsum->nm = datasum1->nm;
	for (int i = 0; i < datasum1->mu; i++) {
		for (int j = 0; j < datasum1->nm; j++) {
			item = getItem(data1, i + 1, j + 1, datasum1) + getItem(data2, i + 1, j + 1, datasum2);
			if (item != 0) {//不是零就加入新的三元组中
				setItem(add, i + 1, j + 1, item);
				addsum->num++;
			}
		}
	}
}

void mulMatrix(Triple *data1, Triple *data2, Matrix *datasum1, Matrix *datasum2, Triple *mul, Matrix *mulsum) {
	if (datasum1->nm != datasum2->mu) { //不满足乘法法则
		printf("violation of calculation rules!\n");
	}
	mulsum->mu = datasum1->mu;
	mulsum->nm = datasum2->nm;
	mulsum->num = 0;
	int sum;
	for (int i = 0; i < datasum1->mu; i++) { //换第一个矩阵行
		for (int j = 0; j < datasum2->nm; j++) { //换第二个矩阵列
			sum = 0;
			for (int k = 0; k < datasum2->mu; k++) { //换第二个矩阵行
				sum += getItem(data1, i + 1, k + 1, datasum1) * getItem(data2, k + 1, j + 1, datasum2);
			}
			if (sum != 0) {//不是零就加入新的三元组中
				setItem(mul, i + 1, j + 1, sum);
				mulsum->num++;
			}
		}
	}
}

(2)稀疏矩阵加乘.c

#include "稀疏矩阵(顺序).h"

main() {
	Triple data1[MAX];
	TripleMatrix(data1);
	Triple data2[MAX];
	TripleMatrix(data2);
	Matrix datasum1;
	Matrix datasum2;
	printf("请输入第1个矩阵初始的行,列和非零元个数:");
	scanf("%d %d %d", &datasum1.mu, &datasum1.nm, &datasum1.num);
	initMatrix(data1, datasum1.num);
	printf("请输入第2个矩阵初始的行,列和非零元个数:");
	scanf("%d %d %d", &datasum2.mu, &datasum2.nm, &datasum2.num);
	initMatrix(data2, datasum2.num);
	printf("请确认您的输入:\n");
	printf("第1个");
	printfMatrix(data1, &datasum1);
	printf("第2个");
	printfMatrix(data2, &datasum2);
	printf("如果要进行相加操作,请输入1;如果要进行相乘操作,请输入2:");
	int type;
	scanf("%d", &type);
	if (type == 1) {
		Triple add[MAX];
		TripleMatrix(add);
		Matrix addsum;
		addMatrix(data1, data2, &datasum1, &datasum2, add, &addsum);
		printf("相加后矩阵为:\n");
		printfMatrix(add, &addsum);
	} else if (type == 2) {
		Triple mul[MAX];
		TripleMatrix(mul);
		Matrix mulsum;
		mulMatrix(data1, data2, &datasum1, &datasum2, mul, &mulsum);
		printf("相乘后矩阵为:\n");
		printfMatrix(mul, &mulsum);
	}
}

void initMatrix(Triple *data, int num) {
	int row, col;
	DataType item;
	for (int i = 0; i < num; i++) { //乱序的,不用从大到小
		printf("请依次输入行,列和非零元:");
		scanf("%d %d %d", &row, &col, &item);
		setItem(data, row, col, item);
	}
}

(3)测试输出

 (验证一下矩阵乘法~这里用的matlab)答案是一致的!

 初学小白,有错误欢迎指正喔!~

有关稀疏矩阵的加法和乘法(三元组)的更多相关文章

  1. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  2. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

  3. ruby-on-rails - 浮点乘法的 Ruby 奇怪问题 - 2

    有没有人用ruby​​解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby​​1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi

  4. 华为OD机试真题 C++ 实现【带传送阵的矩阵游离】【2023 Q2 | 200分】 - 2

            所有题目均有五种语言实现。C实现目录、C++实现目录、Python实现目录、Java实现目录、JavaScript实现目录题目n行m列的矩阵,每个位置上有一个元素你可以上下左右行走,代价是前后两个位置元素值差的绝对值.另外,你最多可以使用一次传送阵(只能从一个数跳到另外一个相同的数)求从走上角走到右下角最少需要多少时间。输入描述:第一行两个整数n,m,分别代表矩阵的行和列。后面n行,每行m个整数,分别代表矩阵中的元素。输出描述:一个整数,表示最少需要多少时间。

  5. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

  6. 欧拉角表示的姿态矩阵(313和312转序) - 2

    一、习惯约定图片来自PSINS(高精度捷联惯导算法)PSINS工具箱入门与详解.pptx二、基本旋转矩阵绕x轴逆时钟旋转α\alphaα角度Rx(α)=[ 1000cos⁡αsin⁡α0−sin⁡αcos⁡α]R_x(\alpha)=\begin{bmatrix}\1&0&0\\0&\cos\alpha&\sin\alpha\\0&-\sin\alpha&\cos\alpha\end{bmatrix}Rx​(α)=​ 100​0cosα−sinα​0sinαcosα​​绕y轴逆时钟旋转α\alphaα角度Ry(α)=[ cos⁡α0−sin⁡α010sin⁡α0cos⁡α]R_y(\alpha

  7. 欧拉角、旋转矩阵及四元数 - 2

    欧拉角、旋转矩阵及四元数1.简介2.欧拉角2.1欧拉角定义2.2右手系和左手系2.3转换流程3.旋转矩阵4.四元数4.1四元数与欧拉角和旋转矩阵之间等效变换4.2测试Matlab代码5.总结1.简介常用姿态参数表达方式包括方向余弦矩阵、欧拉轴/角参数、欧拉角、四元数以及罗德里格参数等。高分辨率光学遥感卫星主要采用欧拉角与四元数对姿态参数进行描述。这里着重讲解欧拉角、旋转矩阵和四元数。2.欧拉角2.1欧拉角定义欧拉角是表征刚体旋转的一种方法之一,由莱昂哈德·欧拉引入的三个角度,用于描述刚体相对于固定坐标系的方向。在摄影测量、空间科学或其它技术领域,一般用一组(三个)欧拉角描述两个空间坐标之间的旋

  8. ruby - 如何使用 RuboCop 强制使用三元括号? - 2

    我有一个编码标准,建议无论表达式如何,三元组的初始参数都应始终在括号内。例如foo=(thing.baz?)?[]:东西.bar以下行为应视为违规:例如foo=thing.baz??[]:东西.bar是否可以使用Rubocop的内置Cops来实现这一点,或者这是否需要自定义Cop。如果可以,我将如何实现? 最佳答案 我看到了你的问题,所以我继续为你实现警察。名称是Style/TernaryParentheses,您想要的EnforcedStyle选项是require_parentheses(不是默认值。)#.rubocop.ymlS

  9. ruby - 可能用三元运算符表达条件 HAML - 2

    试图想出一种更紧凑的方式来在HAML和Ruby中表达这个条件,也许使用三元运算符:-if@page.nil?%br(nothingyet)-else%br#{@page.name}(根据NeatwaytoconditionallytestwhethertoaddaclassinHAMLtemplate寻找类似的方法)您的帮助将不胜感激:) 最佳答案 您的代码使文本成为的子元素元素;这是不可取的。我认为,您真正的意思是:%br-if@page.nil?(nothingyet)-else#{@page.name}为此你可以简单地做:%b

  10. ruby - 如何修改矩阵(Ruby std-lib Matrix 类)? - 2

    我理解RubystdlibMatrix是不可修改的,也就是说,例如。m=Matrix.zero(3,4)不会写m[0,1]=7但我非常想做...我可以用笨拙的编程来做,比如defmodify_value_in_a_matrix(matrix,row,col,newval)ary=(0...m.row_size).map{|i|m.rowi}.map(&:to_a)ary[row][col]=newvalMatrix[*ary]end...或者作弊,比如Matrix.send:[]=,0,1,7但我想知道,这一定是人们一直遇到的问题。有没有一些标准的、习惯的方法可以做到这一点,而不必使用

随机推荐