【数据结构】数组和字符串(七):特殊矩阵的压缩存储:三元组表的转置、加法、乘法操作

文章目录

  • 4.2.1 矩阵的数组表示
  • 4.2.2 特殊矩阵的压缩存储
    • a. 对角矩阵的压缩存储
    • b~c. 三角、对称矩阵的压缩存储
    • d. 稀疏矩阵的压缩存储——三元组表
    • 4.2.3三元组表的转置、加法、乘法、操作
      • 转置
      • 加法
      • 乘法
      • 算法测试
      • 实验结果
      • 代码整合

4.2.1 矩阵的数组表示

【数据结构】数组和字符串(一):矩阵的数组表示

4.2.2 特殊矩阵的压缩存储

  矩阵是以按行优先次序将所有矩阵元素存放在一个一维数组中。但是对于特殊矩阵,如对称矩阵、三角矩阵、对角矩阵和稀疏矩阵等, 如果用这种方式存储,会出现大量存储空间存放重复信息或零元素的情况,这样会造成很大的空间浪费。为节约存储空间和算法(程序)运行时间,通常会采用压缩存储的方法。

  • 对角矩阵:指除了主对角线以外的元素都为零的矩阵,即对 任意 i ≠ j (1≤ i , j ≤n),都有M(i, j)=0。由于只有主对角线上有非零元素,只需存储主对角线上的元素即可。
  • 三角矩阵:指上三角或下三角的元素都为零的矩阵。同样地,只需存储其中一部分非零元素,可以节省存储空间。
  • 对称矩阵:指矩阵中的元素关于主对角线对称的矩阵。由于对称矩阵的非零元素有一定的规律,可以只存储其中一部分元素,从而减少存储空间。
  • 稀疏矩阵:指大部分元素为零的矩阵。传统的按行优先次序存储方法会浪费大量空间来存储零元素,因此采用压缩存储的方法更为合适。常见的压缩存储方法有:压缩稠密行(CSR)、压缩稠密列(CSC)、坐标列表(COO)等。

a. 对角矩阵的压缩存储

【数据结构】数组和字符串(二):特殊矩阵的压缩存储:对角矩阵——一维数组

b~c. 三角、对称矩阵的压缩存储

【数据结构】数组和字符串(三):特殊矩阵的压缩存储:三角矩阵、对称矩阵——一维数组

d. 稀疏矩阵的压缩存储——三元组表

  对于稀疏矩阵的压缩存储,由于非零元素的个数远小于零元素的个数,并且非零元素的分布没有规律,无法简单地利用一维数组和映射公式来实现压缩存储。针对稀疏矩阵,通常采用特定的数据结构来进行压缩存储,以减少存储空间的占用。

  一种常见的稀疏矩阵压缩存储方法是使用"三元组"表示法,也称为COO(Coordinate)格式,只存储非零元素的值以及它们的行列坐标。通过使用三元组(Triplet)来表示非零元素的位置和值,每个三元组包含三个信息:非零元素的行索引、非零元素的列索引以及非零元素的值。

【数据结构】数组和字符串(四):特殊矩阵的压缩存储:稀疏矩阵——三元组表

4.2.3三元组表的转置、加法、乘法、操作

转置

  假设稀疏矩阵存储在一个三元组表a中,且A的非零元素个数为count,算法Transpose求A的转置矩阵并将其保存在三元组表b中。

  • 算法的主要思想是针对每个列号k(k=0, 2,… , n-1)对a进行扫描,考察a中是否有列号为k的结点(注意:列号为k的结点可能不止一个),若有,记为a[u](假定a[u]在a中的行号为i ),将a[u]依次保存在b的b[w] 中,则row(b[w])=k,col(b[w])=i,value(b[w]) =value(a[u]).
    在这里插入图片描述
TripletTable matrixTranspose(TripletTable* table) {TripletTable result;initTable(&result, table->cols, table->rows);  // 转置后的矩阵行列互换int j = 0;for (int k = 0; k < table->cols; k++) {for (int i = 0; i < table->length; i++) {Triple* element = &(table->data[i]);if (element->col == k) {insertElement(&result, k, element->row, element->value);
//                result.data[j].row = k;  // 该元素在result中的行号应为k
//                result.data[j].col = element->row;  // 该元素在result中的列号应为其在table中的行号
//                result.data[j].value = element->value;j++;  // 考察result中的下一个结点result.length = j;  // 更新result的长度}}
//        printf("\n");
//        displayMatrix(&result);}return result;
}

   matrixTranspose函数实现稀疏矩阵的转置操作:

  • 首先,创建一个新的TripletTable变量result,用于存储输入矩阵的转置。
  • 使用initTable函数初始化result,将其行数设置为输入矩阵的列数,列数设置为输入矩阵的行数。
  • 使用一个循环遍历输入矩阵的所有元素:
    • 对于每个元素,将其行号作为转置后矩阵中的列号,列号作为转置后矩阵中的行号,并将值保持不变。
    • 将转置后的元素插入到result中。
  • 返回result作为输入矩阵的转置。

加法

TripletTable matrixAddition(TripletTable* table1, TripletTable* table2) {TripletTable result;initTable(&result, table1->rows, table1->cols);int i = 0, j = 0;while (i < table1->length && j < table2->length) {Triple* element1 = &(table1->data[i]);Triple* element2 = &(table2->data[j]);if (element1->row < element2->row || (element1->row == element2->row && element1->col < element2->col)) {insertElement(&result, element1->row, element1->col, element1->value);i++;} else if (element1->row > element2->row || (element1->row == element2->row && element1->col > element2->col)) {insertElement(&result, element2->row, element2->col, element2->value);j++;} else {int sum = element1->value + element2->value;if (sum != 0) {insertElement(&result, element1->row, element1->col, sum);}i++;j++;}}while (i < table1->length) {Triple* element1 = &(table1->data[i]);insertElement(&result, element1->row, element1->col, element1->value);i++;}while (j < table2->length) {Triple* element2 = &(table2->data[j]);insertElement(&result, element2->row, element2->col, element2->value);j++;}return result;
}

   matrixAddition函数实现稀疏矩阵的加法操作:

  • 创建一个新的TripletTable变量result,用于存储两个输入矩阵的和。
  • 使用initTable函数初始化result,将其行数和列数设置为与输入矩阵相同。
  • 使用两个指针ij分别指向两个输入矩阵的元素。
  • 通过比较当前元素的行号和列号,以及使用循环遍历的方式,将两个输入矩阵的元素逐个比较并进行相应的操作:
    • 如果第一个矩阵的元素在行号和列号上小于第二个矩阵的元素,将第一个矩阵的元素插入到result中,并增加指向第一个矩阵元素的指针i
    • 如果第一个矩阵的元素在行号和列号上大于第二个矩阵的元素,将第二个矩阵的元素插入到result中,并增加指向第二个矩阵元素的指针j
    • 如果两个矩阵的元素在行号和列号上相等,将它们的值相加,并将结果插入到result中。然后,增加指向两个矩阵元素的指针ij
  • 处理完所有元素后,将剩余的未处理元素插入到result中。
  • 返回result作为两个输入矩阵的和。

乘法

TripletTable matrixMultiplication(TripletTable* table1, TripletTable* table2) {TripletTable result;initTable(&result, table1->rows, table2->cols);int matrix[table1->rows][table2->cols];for (int i = 0; i < table1->rows; i++) {for (int j = 0; j < table2->cols; j++) {matrix[i][j] = 0;}}for (int i = 0; i < table1->length; i++) {Triple* element1 = &(table1->data[i]);for (int j = 0; j < table2->length; j++) {Triple* element2 = &(table2->data[j]);if (element1->col == element2->row) {matrix[element1->row][element2->col] += element1->value * element2->value;}}}for (int i = 0; i < table1->rows; i++) {for (int j = 0; j < table2->cols; j++) {if (matrix[i][j] != 0) {insertElement(&result, i, j, matrix[i][j]);}}}return result;
}

   matrixMultiplication函数实现稀疏矩阵的乘法操作:

  • 创建一个新的TripletTable变量result,用于存储两个输入矩阵的乘积。
  • 使用initTable函数初始化result,将其行数设置为第一个输入矩阵的行数,列数设置为第二个输入矩阵的列数。
  • 创建一个临时的二维数组matrix,用于存储两个输入矩阵相乘的结果。
  • matrix中的所有元素初始化为0。
  • 使用两个嵌套的循环遍历第一个输入矩阵的所有元素:
    • 对于每个元素,使用另一个嵌套的循环遍历第二个输入矩阵的所有元素。
    • 如果第一个矩阵的元素的列号等于第二个矩阵的元素的行号,将它们的值相乘,并将结果累加到matrix中对应位置的元素上。
  • 遍历matrix中的所有元素,将非零元素插入到result中。
  • 返回result作为两个输入矩阵的乘积。

算法测试

int main() {TripletTable matrixA, matrixB;initTable(&matrixA, 3, 3);initTable(&matrixB, 3, 3);// Insert elements into matrix AinsertElement(&matrixA, 0, 0, 1);insertElement(&matrixA, 0, 2, 2);insertElement(&matrixA, 1, 1, 3);insertElement(&matrixA, 2, 0, 4);insertElement(&matrixA, 2, 2, 5);// Insert elements into matrix BinsertElement(&matrixB, 0, 1, 6);insertElement(&matrixB, 1, 0, 7);insertElement(&matrixB, 1, 2, 8);insertElement(&matrixB, 2, 1, 9);printf("Matrix A:\n");displayMatrix(&matrixA);printf("\nMatrix B:\n");displayMatrix(&matrixB);TripletTable matrixC = matrixAddition(&matrixA, &matrixB);printf("\nMatrix A + B:\n");displayMatrix(&matrixC);TripletTable matrixD = matrixTranspose(&matrixA);printf("\nTranspose of Matrix A:\n");displayMatrix(&matrixD);TripletTable matrixE = matrixMultiplication(&matrixA, &matrixB);printf("\nMatrix A * B:\n");displayMatrix(&matrixE);return 0;
}

实验结果

在这里插入图片描述

代码整合

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 10typedef struct {int row;int col;int value;
} Triple;typedef struct {Triple data[MAX_SIZE];int rows;int cols;int length;
} TripletTable;void initTable(TripletTable* table, int rows, int cols) {table->rows = rows;table->cols = cols;table->length = 0;memset(table->data, 0, sizeof(Triple) * MAX_SIZE);  // 新添加
}void insertElement(TripletTable* table, int row, int col, int value) {if (table->length >= MAX_SIZE) {printf("Table is full. Cannot insert more elements.\n");return;}Triple* element = &(table->data[table->length]);element->row = row;element->col = col;element->value = value;table->length++;
}void displayMatrix(TripletTable* table) {int matrix[table->rows][table->cols];for (int i = 0; i < table->rows; i++) {for (int j = 0; j < table->cols; j++) {matrix[i][j] = 0;}}
//    printf("Row\tColumn\tValue\n");for (int i = 0; i < table->length; i++) {Triple* element = &(table->data[i]);
//        printf("%d\t%d\t%d\n", element->row, element->col, element->value);matrix[element->row][element->col] = element->value;}//    printf("Matrix:\n");for (int i = 0; i < table->rows; i++) {for (int j = 0; j < table->cols; j++) {printf("%d\t", matrix[i][j]);}printf("\n");}
}
TripletTable matrixAddition(TripletTable* table1, TripletTable* table2) {TripletTable result;initTable(&result, table1->rows, table1->cols);int i = 0, j = 0;while (i < table1->length && j < table2->length) {Triple* element1 = &(table1->data[i]);Triple* element2 = &(table2->data[j]);if (element1->row < element2->row || (element1->row == element2->row && element1->col < element2->col)) {insertElement(&result, element1->row, element1->col, element1->value);i++;} else if (element1->row > element2->row || (element1->row == element2->row && element1->col > element2->col)) {insertElement(&result, element2->row, element2->col, element2->value);j++;} else {int sum = element1->value + element2->value;if (sum != 0) {insertElement(&result, element1->row, element1->col, sum);}i++;j++;}}while (i < table1->length) {Triple* element1 = &(table1->data[i]);insertElement(&result, element1->row, element1->col, element1->value);i++;}while (j < table2->length) {Triple* element2 = &(table2->data[j]);insertElement(&result, element2->row, element2->col, element2->value);j++;}return result;
}TripletTable matrixMultiplication(TripletTable* table1, TripletTable* table2) {TripletTable result;initTable(&result, table1->rows, table2->cols);int matrix[table1->rows][table2->cols];for (int i = 0; i < table1->rows; i++) {for (int j = 0; j < table2->cols; j++) {matrix[i][j] = 0;}}for (int i = 0; i < table1->length; i++) {Triple* element1 = &(table1->data[i]);for (int j = 0; j < table2->length; j++) {Triple* element2 = &(table2->data[j]);if (element1->col == element2->row) {matrix[element1->row][element2->col] += element1->value * element2->value;}}}for (int i = 0; i < table1->rows; i++) {for (int j = 0; j < table2->cols; j++) {if (matrix[i][j] != 0) {insertElement(&result, i, j, matrix[i][j]);}}}return result;
}TripletTable matrixTranspose(TripletTable* table) {TripletTable result;initTable(&result, table->cols, table->rows);  // 转置后的矩阵行列互换int j = 0;for (int k = 0; k < table->cols; k++) {for (int i = 0; i < table->length; i++) {Triple* element = &(table->data[i]);if (element->col == k) {insertElement(&result, k, element->row, element->value);
//                result.data[j].row = k;  // 该元素在result中的行号应为k
//                result.data[j].col = element->row;  // 该元素在result中的列号应为其在table中的行号
//                result.data[j].value = element->value;j++;  // 考察result中的下一个结点result.length = j;  // 更新result的长度}}
//        printf("\n");
//        displayMatrix(&result);}return result;
}int main() {TripletTable matrixA, matrixB;initTable(&matrixA, 3, 3);initTable(&matrixB, 3, 3);// Insert elements into matrix AinsertElement(&matrixA, 0, 0, 1);insertElement(&matrixA, 0, 2, 2);insertElement(&matrixA, 1, 1, 3);insertElement(&matrixA, 2, 0, 4);insertElement(&matrixA, 2, 2, 5);// Insert elements into matrix BinsertElement(&matrixB, 0, 1, 6);insertElement(&matrixB, 1, 0, 7);insertElement(&matrixB, 1, 2, 8);insertElement(&matrixB, 2, 1, 9);printf("Matrix A:\n");displayMatrix(&matrixA);printf("\nMatrix B:\n");displayMatrix(&matrixB);TripletTable matrixC = matrixAddition(&matrixA, &matrixB);printf("\nMatrix A + B:\n");displayMatrix(&matrixC);TripletTable matrixD = matrixTranspose(&matrixA);printf("\nTranspose of Matrix A:\n");displayMatrix(&matrixD);TripletTable matrixE = matrixMultiplication(&matrixA, &matrixB);printf("\nMatrix A * B:\n");displayMatrix(&matrixE);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/120974.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

竞赛 深度学习实现行人重识别 - python opencv yolo Reid

文章目录 0 前言1 课题背景2 效果展示3 行人检测4 行人重识别5 其他工具6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的行人重识别算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

论文阅读——BART

Arxiv: https://arxiv.org/abs/1910.13461 一个去噪自编码器的预训练序列到序列的模型。是一个结合了双向和自回归transformers的模型。 预训练分为两个阶段&#xff1a;任意噪声函数破坏文本和序列模型重建原始文本 一、模型 input&#xff1a;被破坏的文本-->bidirecti…

基于Canal同步MySQL数据到Elasticsearch

基于Canal同步MySQL数据到Elasticsearch 基于 canal 同步 mysql 的数据到 elasticsearch 中。 1、canal-server 相关软件的安装请参考&#xff1a;《Canal实现数据同步》 1.1 pom依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmln…

1. 两数之和、Leetcode的Python实现

博客主页&#xff1a;&#x1f3c6;看看是李XX还是李歘歘 &#x1f3c6; &#x1f33a;每天分享一些包括但不限于计算机基础、算法等相关的知识点&#x1f33a; &#x1f497;点关注不迷路&#xff0c;总有一些&#x1f4d6;知识点&#x1f4d6;是你想要的&#x1f497; ⛽️今…

虚拟机构建部署单体项目及前后端分离项目

目录 一.部署单体项目 1.远程数据库 1.1远程连接数据库 1.2 新建数据库运行sql文件 2.部署项目到服务器中 3.启动服务器运行 二.部署前后端分离项目 1.远程数据库和部署到服务器 2.利用node环境启动前端项目 3.解决主机无法解析服务器localhost问题 方法一 ​编辑 方法二 一.部…

不需要报班学课程,也能制作手办创业的新方法!

近些年&#xff0c;我们已经习惯只要走进商场就一定会路过泡泡玛特一类的潮流玩具店&#xff0c;甚至还会在美食城、自助饮料机旁边看到盲盒手办的售卖机器里摆放着诱人的近期热卖盲盒。一线城市如此&#xff0c;县城也是一样&#xff0c;不同的只可能是盲盒里的内容。 盲盒到底…

公司如何禁止拷贝文件

公司如何禁止拷贝文件 安企神U盘管理系统下载使用 禁止拷贝文件是一种数据安全措施&#xff0c;通常在企业中用于保护重要信息和知识产权。禁止拷贝文件的方法需要根据公司的实际情况来选择和实施&#xff0c;以下是一些常见的方法&#xff0c;可用于防止文件拷贝&#xff1a…

【pwn入门】使用python打二进制

声明 本文是B站你想有多PWN学习的笔记&#xff0c;包含一些视频外的扩展知识。 程序网络交互初体验 将程序部署成可以远程访问的 socat tcp-l:8877,fork exec:./question_1_plus_x64,reuseaddr通过网络访问程序 nc 127.0.0.1 8877攻击脚本 import socket import telnetli…

【C语言】字符函数与字符串函数

简单不先于复杂&#xff0c;而是在复杂之后。 目录 0. 前言 1. 函数介绍 1.1 strlen 1.1.1 介绍 1.1.2 strlen 函数模拟实现 1.1.2.1 计数器方法 1.1.2.2 递归方法 1.1.2.3 指针 - 指针方法 1.2 strcpy 1.2.1 介绍 1.2.2 strcpy 函数模拟实现 1.3 strcat 1…

RuoYi-Vue-SqlServer配置

项目链接 https://gitee.com/linkxs/RuoYi-Vue-SqlServerhttps://gitee.com/linkxs/RuoYi-Vue-SqlServer 服务端Eclipse编译 需要在 /ruoyi-common/pom.xml 中注释掉这些exclusion才能在Eclipse编译。实际maven编译&#xff0c;可以把这一块打开。 客户端ruoyi-ui编译 使用…

【Unity实战】手戳一个自定义角色换装系统——2d3d通用

文章目录 每篇一句前言素材开始切换头型添加更改颜色随机控制头型和颜色新增眼睛同样的方法配置人物的其他部位设置相同颜色部位全部部位随机绘制UI并添加点击事件通过代码控制点击事件添加颜色修改的事件其他部位效果UI切换添加随机按钮保存角色变更数据跳转场景显示角色数据 …

Python-自动化绘制股票价格通道线

常规方案 通过将高点/低点与其 2 个或 3 个相邻点进行比较来检测枢轴点,并检查它是否是其中的最高/最低点。对所有枢轴点进行线性回归以获得上方和下方趋势线。价格离开通道后建仓。通过这样做,我们得到如下所示的价格通道。我认为我们可以利用给定的数据取得更好的结果。

【算法|动态规划No30】leetcode5. 最长回文子串

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

C语言之预处理

目录 前言 宏定义define的用法 文件包含include的用法 条件编译的用法 其他预处理命令 练习题 练习一 练习二 练习三 前言 预处理命令可以改变程序设计环境&#xff0c;提高编程效率&#xff0c;它们并不是C语言本身的组成部分&#xff0c;不能直接对它们进行编译&am…

redis高可用

文章目录 redis高可用概述哨兵模式原理配置流程使用缺点 cluster集群原理特征流程缺点故障转移故障检测故障转移 集群配置和管理主要命令搭建集群创建集群查看集群配置信息测试集群主从切换扩容缩容 redis高可用概述 1、高可用是分布式的概念。 Redis的高可用性是指在Redis集群…

springsecurity学习笔记-未完

目录 前言 一、概念 1.什么是springsecurity 2.对比shiro 二、开始项目 1.建立一个空项目&#xff0c;建立module&#xff0c;引入相关依赖 2.启动项目&#xff0c;访问项目 3.自定义密码 总结 前言 记录一下学习springsecurity的过程 开发环境&#xff1a;IDEA 一、概念 1.…

解决提交到App Store时的ITMS-90478和ITMS-90062错误

解决提交到App Store时的ITMS-90478和ITMS-90062错误 目录 引言 正文 1. 什么是ITMS-90478和ITMS-90062错误&#xff1f; 2. 解决方法 2.1 确定当前的版本号和构建号 2.2 递增版本号和构建号 2.3 再次尝试提交应用 总结 参考资料 错误记录 摘要&#xff1a;本文为iOS…

鼎鑫鸿鄴引入“能源互联网+”理念 打造共赢

近年来&#xff0c;随着全球能源消耗的不断增长和环境问题的日益突出&#xff0c;清洁能源转型成为全球共同关注的话题。中国作为全球最大的能源消费国&#xff0c;也在积极推动能源结构的优化和清洁能源的发展。鼎鑫鸿鄴新能源科技有限公司在推动清洁能源转型方面制定了一系列…

北太天元安装教程 及使用方法

北太天元是面向科学计算与工程计算的国产通用型科学计算软件。提供科学计算、可视化、交互式程序设计&#xff0c;具备丰富的底层数学函数库&#xff0c;支持数值计算、数据分析、数据可视化、数据优化、算法开发等工作&#xff0c;并通过SDK与API接口&#xff0c;扩展支持各类…

Vite介绍及实现原理

Vite介绍及实现原理 一、Vite简介1.1、什么是Vite1.2 、Vite的主要特性1.3、 为什么要使用Vite 二、Vite的实现原理2.1、依赖处理2.2、静态资源加载2.3、vue文件缓存2.4、 js/ts处理 三、热更新原理四、vite基本使用4.1、安装4.2、搭建项目 一、Vite简介 1.1、什么是Vite Vite…