稀疏矩阵及其转置

稀疏矩阵三元组存储与转置

系数矩阵的存储方式:三元组

typedef struct TRIPLE_ELEMENT {
	int data;
	int row;
	int col;
}TRIPLE_ELEMENT;

三元组用于存储矩阵的每一个元素
额外需要一个表头来表示整个矩阵:

typedef struct TRIPLE_MATRIX {
	TRIPLE_ELEMENT *elementList;
	int maxRow;
	int maxCol;
	int elementCount;
}TRIPLE_MATRIX;

初始化及输入矩阵:

TRIPLE_MATRIX *initTripleMatrix(int maxRow, int maxCol, int elementCount) {
	TRIPLE_MATRIX *result = NULL;

	result = (TRIPLE_MATRIX *) calloc(sizeof(TRIPLE_MATRIX), 1);
	result->elementList = (TRIPLE_ELEMENT *)
			calloc(sizeof(TRIPLE_ELEMENT), elementCount);
	result->maxRow = maxRow;
	result->maxCol = maxCol;
	result->elementCount = elementCount;

	return result;
}

初始化矩阵需要动态申请两个空间:①表头(指向矩阵) ②元素个数为elementcount的数组(用于存储矩阵各元素)

void inputTripleMatrix(const TRIPLE_MATRIX *matrix) {
	int index = 0;
	int count = matrix->elementCount;
	int row;
	int col;
	int data;
	
	for (index = 0; index < count; index++) {
		scanf("%d%d%d", &row, &col, &data);
		matrix->elementList[index].row = row;
		matrix->elementList[index].col = col;
		matrix->elementList[index].data = data;
	}
}

由用户输入矩阵内容

以上两个函数都比较好理解,没有太多需要深入思考的问题

打印矩阵:

void showTripleMatrix(const TRIPLE_MATRIX *matrix) {
	int row;
	int col;
	int index = 0;

	for (row = 0; row < matrix->maxRow; row++) {
		for (col = 0; col < matrix->maxCol; col++) {
			if (row == matrix->elementList[index].row
					&& col == matrix->elementList[index].col) {
				printf("%4d", matrix->elementList[index].data);
				index++;
			} else {
				printf("%4d", 0);
			}
		}
		printf("\n");
	}
}

表面是遍历矩阵数据数组完成遍历,实际隐藏的内部逻辑有 需要矩阵元素数组先按行升序,同行需要按列升序
这为矩阵的转置添加了一个难题

转置矩阵:
我们的手工过程通常是直接将行列转换即可,但是由于打印矩阵函数的内部逻辑,我们交转行列还需要进行排序,
最笨的办法就是数组内的元素直接交换行列,再依据行列依次升序排列即可。
但是有更方便的办法:

indexArr = (int *) calloc(sizeof(int), matrix->maxCol + 1);
	for (index = 0; index < matrix->elementCount; index++) {
		indexArr[matrix->elementList[index].col + 1]++;
	}

我们首先构建一个数组, 目的是统计出转置后当前行上一行的非零元素个数在这里插入图片描述

在这里插入图片描述
例如这组数据,转置后的第七行前一行第六行按数组表示有两个元素。

for (index = 1; index < matrix->maxCol + 1; index++) {
		indexArr[index] += indexArr[index - 1];
	}

接着数组初始化完成后,再进行一次追加操作,这样数组含义就发生了改变:
在这里插入图片描述
当前数组下标为转置后的行,其对应的数组元素表示此行第一个元素在数组中对应的下标。
因为追加之前表示的是该行上一行有效元素个数,那么追加后就是该行之前全部有效元素个数,而矩阵数据数组就是用来存放有效数组,下标就是该数据之前的有效元素个数,所以这两个数值是对应的。

在这里插入图片描述
左侧是转置前的元素,右侧是转置后的,按照我们制造出来的数组,转置后第七行(转之前第七列)的第一个元素应该在第九个位置存储。

通过这个数组和矩阵,我们就可以得出转置前的元素及其位置,还有转置后每行第一个非零元素在矩阵数组中的存储位置。

result = initTripleMatrix(matrix->maxCol, matrix->maxRow, matrix->elementCount);

	for (index = 0; index < matrix->elementCount; index++) {
		colIndex = matrix->elementList[index].col;
		result->elementList[indexArr[colIndex]].row = matrix->elementList[index].col;
		result->elementList[indexArr[colIndex]].col = matrix->elementList[index].row;
		result->elementList[indexArr[colIndex]].data = matrix->elementList[index].data;
		indexArr[colIndex]++;
	}

接下来申请一个新的表头指向转置后的矩阵,开始转置工作。
首先数组下标对应的是转置后的行(即转置前的列),首先取出即将要操作的行,indexArr[colIndex]可取出 当前行第一个有效元素在转置后的元素数组中的下标(即我们找到了转置后元素所要存放的位置),找到位置下一步就进行赋值操作,行列互换,值不变。
在我们赋值过后,有一个细节,我们现在对该行第一个元素进行赋值,因为我们的矩阵先后按行按列升序排序,所以在矩阵元素数组中同一行下一个元素一定在同一行上一个元素紧挨着之后存放。
当前行第一个有效元素位置indexArr[colIndex], 那么下一个有效元素位置就是上一个有效元素的下一个位置,即indexArr[colIndex]++即可

总结
重点思想是矩阵转置中对转置后元素所存下标进行获取,通过得到每一前行有效元素个数,再进行追加就能得到前所有行的有效元素个数,这样和转置后矩阵数据数组的下标意义相同。

### COO Format 稀疏矩阵简介 `coo_matrix` 是 SciPy 中一种用于表示稀疏矩阵的数据结构,属于 Coordinate (COO) 格式。这种格式通过分别存储非零元素的值以及它们对应的行索引和列索引来实现高效的内存利用[^1]。 #### `coo_matrix` 的基本属性 - **数据存储方式**: 非零元素被分为三个数组来存储:`data`, `row`, 和 `col`。 - `data`: 存储所有的非零元素值。 - `row`: 对应于 `data` 数组中每个非零元素所在的行号。 - `col`: 对应于 `data` 数组中每个非零元素所在的列号。 - **适用场景**: 当需要频繁构建或修改稀疏矩阵时,`coo_matrix` 提供了一个简单直观的方式[^4]。 --- ### Python 示例代码 以下是创建和操作 `coo_matrix` 的具体示例: ```python from scipy.sparse import coo_matrix import numpy as np # 定义非零元素的位置和值 data = np.array([3, 5, 7]) # 非零元素的值 rows = np.array([0, 2, 1]) # 行索引 cols = np.array([1, 0, 2]) # 列索引 # 构造一个形状为 (3, 3) 的 COO 格式的稀疏矩阵 sparse_matrix = coo_matrix((data, (rows, cols)), shape=(3, 3)) print("稀疏矩阵:") print(sparse_matrix) # 转换为密集矩阵查看效果 dense_matrix = sparse_matrix.toarray() print("\n转换后的密集矩阵:") print(dense_matrix) ``` 上述代码展示了如何使用 `coo_matrix` 来定义一个简单的稀疏矩阵,并将其转化为稠密矩阵以便观察其内容。 --- ### 将 COO 格式保存为 Mtx 文件 如果希望将 `coo_matrix` 保存到外部文件中,可以采用 `.mtx` 格式。这是一种标准的文本文件格式,专门设计用来存储稀疏矩阵的信息[^3]。 下面是具体的保存过程: ```python from scipy import sparse import scipy.io as sio # 创建随机稀疏矩阵 matrix = sparse.random(10, 10, density=0.2, format='coo') # 保存为 .mtx 文件 sio.mmwrite('sparse_matrix.mtx', matrix) print("稀疏矩阵已成功保存至 'sparse_matrix.mtx'") ``` 此部分演示了如何借助 `scipy.io.mmwrite()` 方法导出 `coo_matrix` 数据。 --- ### 注意事项 尽管 `coo_matrix` 在构建阶段非常方便,但它并不支持就地修改(即无法直接更改其中的元素)。因此,在完成初始构造之后,通常会将其转换成其他更适合计算的形式,比如 CSR 或 CSC 格式。 例如: ```python csr_matrix = sparse_matrix.tocsr() # 转换为 CSR 格式 csc_matrix = sparse_matrix.tocsc() # 转换为 CSC 格式 ``` 这些格式允许更高效的算术运算和切片访问。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值