数据结构与算法教程,数据结构C语言版教程!(第五部分、数组和广义表详解)四

 第五部分、数组和广义表详解

数组和广义表,都用于存储逻辑关系为“一对一”的数据。

数组存储结构,99% 的编程语言都包含的存储结构,用于存储不可再分的单一数据;而广义表不同,它还可以存储子广义表。

本章重点从矩阵的角度讨论二维数组的存储,同时讲解广义表的存储结构以及有关其广度和深度的算法实现。

七、矩阵(稀疏矩阵)的转置算法(C语言)详解

矩阵(包括稀疏矩阵)的转置,即互换矩阵中所有元素的行标和列标,如图 1 所示:

图 1 矩阵转置示意图

但如果想通过程序实现矩阵的转置,互换行标和列标只是第一步。因为实现矩阵转置的前提是将矩阵存储起来,数据结构中提供了 3 种存储矩阵的结构,分别是三元组顺序表、行逻辑链接的顺序表和十字链表如果采用前两种结构,矩阵的转置过程会涉及三元组表也跟着改变的问题,如图 2 所示:

图 2 三元组表的变化

图 2a) 表示的是图 1 中转置之前矩阵的三元组表,2b) 表示的是图 1 中矩阵转置后对应的三元组表。

不仅如此,如果矩阵的行数和列数不等,也需要将它们互换。

因此通过以上分析,矩阵转置的实现过程需完成以下 3 步:

  1. 将矩阵的行数和列数互换;
  2. 将三元组表(存储矩阵)中的 i 列和 j 列互换,实现矩阵的转置;
  3. 以 j 列为序,重新排列三元组表中存储各三元组的先后顺序;

此 3 步中,前两步比较简单,关键在于最后一步的实现。本节先介绍较容易的一种。

矩阵转置的实现思路是:不断遍历存储矩阵的三元组表,每次都取出表中 j 列最小的那一个三元组,互换行标和列标的值,并按次序存储到一个新三元组表中。

例如,将图 2a) 三元组表存储的矩阵进行转置的过程为:

  1. 新建一个三元组表(用于存储转置矩阵),并将原矩阵的行数和列数互换赋值给新三元组;
  2. 遍历三元组表,找到表中 j 列最小值 1 所在的三元组 (3,1,6),然后将其行标和列标互换后添加到一个新的三元组表中,如图 3 所示:

    图 3 矩阵转置的第一个过程

  3. 继续遍历三元组表,找到表中 j 列次小值为 2 的三元组,分别为 (1,2,1)、(2,2,3) 和 (3,2,5),根据找到它们的先后次序将各自的行标和列标互换后添加到新三元组表中,如图 4 所示:

    图 4 矩阵转置的第二个过程

对比图 4 和图 2b) 可以看到,矩阵被成功地转置。

因此,矩阵转置的 C 语言实现代码为:

#include<stdio.h>

#define number 10

typedef struct {    

        int i, j;    

        int data;

}triple;

typedef struct {    

        triple data[10];    

        int n, m, num;

}TSMatrix;

TSMatrix transposeMatrix(TSMatrix M, TSMatrix T) {    

        T.m = M.n;    

        T.n = M.m;    

        T.num = M.num;    

        if (T.num) {        

                int q = 0;        

                for (int col = 1; col <= M.m; col++) {            

                        for (int p = 0; p < M.num; p++) {                

                                if (M.data[p].j == col) {                    

                                        T.data[q].i = M.data[p].j;                    

                                        T.data[q].j = M.data[p].i;                    

                                        T.data[q].data = M.data[p].data;                    

                                        q++;                

                                }            

                        }        

                }    

        }    

        return T;

}

int main() {    

        TSMatrix M;    

        M.m = 2;    

        M.n = 3;    

        M.num = 4;    

        M.data[0].i = 1;    

        M.data[0].j = 2;    

        M.data[0].data = 1;    

        M.data[1].i = 2;    

        M.data[1].j = 2;    

        M.data[1].data = 3;  

  

        M.data[2].i = 3;    

        M.data[2].j = 1;    

        M.data[2].data = 6;    

        M.data[3].i = 3;    

        M.data[3].j = 2;    

        M.data[3].data = 5;    

        TSMatrix T;    

        for (int k = 0; k < number; k++) {        

                T.data[k].i = 0;        

                T.data[k].j = 0;        

                T.data[k].data = 0;    

        }    

        T = transposeMatrix(M, T);    

        for (int i = 0; i < T.num; i++) {        

                printf("(%d,%d,%d)\n", T.data[i].i, T.data[i].j, T.data[i].data);    

        }    

        return 0;

}

程序运行结果为:

(1,3,6)
(2,1,1)
(2,2,3)
(2,3,5)

由于此算法中嵌套使用了两个 for 循环,时间复杂度为O(n^{2})。


 八、稀疏矩阵的快速转置算法(C语言)详解

《矩阵的转置算法》一节介绍了实现矩阵转置的普通算法,该算法的时间复杂度为O(n^{2}。本节给大家介绍一种实现矩阵转置更高效的算法,通常称为稀疏矩阵的快速转置算法。

我们知道,稀疏矩阵的转置需要经历以下 3 步:

  1. 将矩阵的行数和列数互换;
  2. 将三元组表(存储矩阵)中的 i 列和 j 列互换,实现矩阵的转置;
  3. 以 j 列为序,重新排列三元组表中存储各三元组的先后顺序;

稀疏矩阵快速转置算法和普通算法的区别仅在于第 3 步,快速转置能够做到遍历一次三元组表即可完成第 3 步的工作。

稀疏矩阵和对应的三元组表

图 1 稀疏矩阵和对应的三元组表

如图 1 所示,此为转置之前的矩阵和对应的三元组表。稀疏矩阵的快速转置是这样的,在普通算法的基础上增设两个数组(假设分别为 array 和 copt):

  • array 数组负责记录原矩阵每一列非 0 元素的个数。以图 1 为例,则对应的array数组如图 2 所示:

    图 2 每一列非 0 元素的个数

    图 2 中 array 数组表示,原稀疏矩阵中第一列有 1 个非 0 元素,第二列有 2 个非 0 元素。
  • copt 数组用于计算稀疏矩阵中每列第一个非 0 元素在新三元组表中存放的位置。我们通常默认第一列首个非 0 元素存放到新三元组表中的位置为 1,然后通过 cpot[col] = cpot[col-1] + array[col-1] 公式可计算出后续各列首个非 0 元素存放到新三元组表的位置。拿图 1 中的稀疏矩阵来说,它对应的 copt 数组如图 3 所示:

    图 3 copt 数组示意图

    图 3 中的 copt 数组表示,原稀疏矩阵中第 2 列首个非 0 元素存放到新三元组表的位置为 2。

注意,cpot[col] = cpot[col-1] + array[col-1] 的意思是,后一列首个非 0 元素存放的位置等于前一列首个非 0 元素的存放位置加上该列非 0 元素的个数。由此可以看出,copt 数组才是最终想要的,而 array 数组的设立只是为了帮助我们得到 copt 数组。

这样在实现第 3 步时,根据每个三元组中 j 的数值,可以借助 cpot 数组直接得到此三元组新的存放位置,C 语言实现代码如下:

//实现快速转置算法的函数

TSMatrix fastTransposeMatrix(TSMatrix M,TSMatrix T){

//第1步:行和列置换

        T.m=M.n;

        T.n=M.m;

        T.num=M.num;

        if (T.num) {

                //计算array数组

                int array[number];

                for (int col=1; col<=M.m; col++) {

                        array[col]=0;

                }

                for (int t=0; t<M.num; t++) {

                        int j=M.data[t].j;

                        array[j]++;

                }

                //创建并初始化cpot数组

                int cpot[T.m+1];

                cpot[1]=1;//第一列中第一个非0元素的位置默认为1

                for (int col=2; col<=M.m; col++) {

                        cpot[col]=cpot[col-1]+array[col-1];

                }

                //遍历一次即可实现三元组表的转置

                for (int p=0; p<M.num; p++) {

                        //提取当前三元组的列数

                        int col=M.data[p].j; /

                        /根据列数和cpot数组,找到当前元素需要存放的位置

                        int q=cpot[col];

                        //转置矩阵的三元组默认从数组下标0开始,而得到的q值是单纯的位置,所以要减1

                        T.data[q-1].i=M.data[p].j;

                        T.data[q-1].j=M.data[p].i;

                        T.data[q-1].data=M.data[p].data ;

                        //存放完成后,cpot数组对应的位置要+1,以便下次该列存储下一个三元组

                        cpot[col]++;

                }

        }

        return T;

}


使用 fastTransposeMatrix 函数实现图 1 中稀疏矩阵转置的 C 语言完整程序为:

#include<stdio.h>

#define number 10

typedef struct {

        int i,j;

        int data;

}triple;

typedef struct {

        triple data[number];

        int rpos[number];

        int n,m,num;

}TSMatrix;

//fastTransposeMatrix放置位置

int main() {

        TSMatrix M;

        M.m=2;

        M.n=3;

        M.num=3;

        M.data[0].i=1;

        M.data[0].j=2;

        M.data[0].data=1;

        M.data[1].i=2;

        M.data[1].j=2;

        M.data[1].data=3;

        M.data[2].i=3;

        M.data[2].j=1;

        M.data[2].data=6;

        TSMatrix T;

        T=fastTransposeMatrix(M, T);

        printf("转置矩阵三元组表为:\n");

        for (int i=0; i<T.num; i++) {

                printf("(%d,%d,%d)\n",T.data[i].i,T.data[i].j,T.data[i].data);

        }

        return 0;

}

程序运行结果为:

转置矩阵三元组表为:
(1,3,6)
(2,1,1)
(2,2,3)

可以看出,稀疏矩阵快速转置算法的时间复杂度为 O(n)。即使在最坏的情况下(矩阵中全部都是非 0 元素),该算法的时间复杂度也才为O(n^{2}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【工具使用】Keil5软件使用-基础使用篇

一、概述 本文面向未接触过Keil的新手&#xff0c;如果是职场老手可跳过此篇。为了快速上手&#xff0c;本文会跳过很多细节及解释&#xff0c;如需要了解原理&#xff0c;请移步进阶篇。 二、 软件介绍 Keil提供了包括C编译器、宏汇编、链接器、库管理和一个功能强大的仿真调…

【Git不走弯路】(二)提交与分支的本质

1. 前言 提交与分支是Git中两个基本对象&#xff0c;对初学者而言需要花些时间理解。正如我们之前所说&#xff0c;计算机中很多新概念是新瓶装旧酒。计算机技术来源于需求&#xff0c;服务于需求&#xff0c;需求是计算机技术的出发点和落脚点。梳理清楚工程实践中&#xff0…

【开源】基于JAVA的停车场收费系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 停车位模块2.2 车辆模块2.3 停车收费模块2.4 IC卡模块2.5 IC卡挂失模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 停车场表3.2.2 车辆表3.2.3 停车收费表3.2.4 IC 卡表3.2.5 IC 卡挂失表 四、系统实现五、核心代码…

2023.1.21 关于 Redis 主从复制详解

目录 引言 单点问题 分布式系统 ​​​​​​​​​​​​​​主从模式 配置 Redis 主从结构 断开主从关系 切换主从关系 补充知识点一 只读 网络延迟 拓扑结构 一主一从 一主多从 树形主从结构 主从复制的基本流程 数据同步 replicationid offset pzync 运…

transdata笔记:手机数据处理

1 mobile_stay_duration 每个停留点白天和夜间的持续时间 transbigdata.mobile_stay_duration(staydata, col[stime, etime], start_hour8, end_hour20) 1.1 主要参数 staydata停留数据&#xff08;每一行是一条数据&#xff09;col 列名&#xff0c;顺序为[‘starttime’,…

终极解决Flutter项目运行ios项目报错Without CocoaPods, plugins will not work on iOS or macOS.

前言 最近在开发Flutter项目&#xff0c;运行ios环境的时候报错没有CocoaPods&#xff0c;安卓环境可以正常运行&#xff0c;当时一脸懵逼&#xff0c;网上搜索了一下&#xff0c;有给我讲原理的&#xff0c;还有让我安装这插件那插件的&#xff0c;最终把电脑搞得卡死&#x…

代码随想录算法训练DAY25|回溯2

算法训练DAY25|回溯2 216.组合总和III 力扣题目链接 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。 解集不能包含重复的组合。 示例 1: 输入: k 3, n …

Docker安装启动、常用命令、应用部署、迁移备份、Dockerfile、Docker私有仓库

目录 1.Docker安装与启动 1.1 安装Docker 1.2 设置ustc的镜像 1.3 Docker的启动与停止 2.常用命令 2.1 镜像相关命令 2.1.1 查看镜像 2.1.2 搜索镜像 2.1.3 拉取镜像 2.1.4 删除镜像 2.2 容器相关命令 2.2.1 查看容器 2.2.2 创建与启动容器 2.2.3 停止与启动容器 2.…

分享flask_socketio配置时遇到的一些问题

flask_socketio 1.前言 flask_socketio应用启动后&#xff0c;在控制台中&#xff0c;存在着flask_socketio这些烦人的log 一堆的get和post几秒一个让我什么都看不清&#xff0c;因此想要关掉log 结果没想到&#xff0c;找了很多办法半天去不掉flask_socketio的log 试过了…

互联网未来的 3 个愿景

互联网可能是现代技术最伟大的创造&#xff0c;而且它是一项正在进行中的工作。其持续发展的核心是对互联网未来发展的三种不同愿景。在本文中&#xff0c;我们将探讨指导互联网技术和架构未来的三个想法&#xff1a;Web 3.0、Web3 和语义 Web。 Web 3.0&#xff1a;互联网的未…

自然语言处理研究的内容

一.基础技术 1.1 词法分析 词法分析&#xff08;Lexical Analysis&#xff09;&#xff0c;也称为词法扫描或扫描器&#xff0c;是自然语言处理&#xff08;NLP&#xff09;中的基础步骤之一&#xff0c;用于将输入的文本分割成词法单元&#xff08;Token&#xff09;。词法单…

Proxmox VE 8 试装Oracle 23c

作者&#xff1a;田逸&#xff08;formyz&#xff09; Oracle 当前的最新版本是23c&#xff0c;虽然官方网站下载不了它的正式版本&#xff0c;但是却提供了一个性能受限的免费版本“Oracle Database 23.3 Free”&#xff08;存储容量受限、内存使用受限&#xff09;。这里就只…

【llm 使用llama 小案例】

huggingfacehttps://huggingface.co/meta-llama from transformers import AutoTokenizer, LlamaForCausalLMPATH_TO_CONVERTED_WEIGHTS PATH_TO_CONVERTED_TOKENIZER # 一般和模型地址一样model LlamaForCausalLM.from_pretrained(PATH_TO_CONVERTED_WEIGHTS) tokenize…

CGLIB动态代理(AOP原理)(面试重点)

推荐先看JDK 动态代理&#xff08;Spring AOP 的原理&#xff09;&#xff08;面试重点&#xff09; JDK 动态代理与 CGLIB 动态代理的区别 JDK 动态代理有⼀个最致命的问题是其只能代理实现了接⼝的类. 有些场景下,我们的业务代码是直接实现的,并没有接⼝定义.为了解决这个问…

一.初识Linux 1-3操作系统概述Linux初识虚拟机介绍

目录 一.初识Linux 1.操作系统概述 计算机组成 硬件&#xff1a; 软件&#xff1a; 操作系统&#xff1a; 操作系统工作流程 操作系统作用 常见的操作系统 PC端&#xff1a; 移动端&#xff1a;&#xff08;掌上操作系统&#xff09; 一.初识Linux 2.Linux初识 linu…

HTML 入门手册(一)

目录 HTML 1-基础语法 单标签 双标签 整体结构 2-标题和水平线 标题 水平线 3-段落和换行 段落 换行 4-列表 无序列表 有序列表 嵌套列表 5-div和span div span 6-格式化标签 粗体 斜体 下划线中划线 上标和下标 7-超链接(a标签) 链接到URL 链接到本…

php基础学习之代码框架

一&#xff0c;标记 脚本标记&#xff08;已弃用&#xff09;&#xff1a;<script language"php"> php代码 </script> 标准标记&#xff1a;<?php php代码 ?> 二&#xff0c;基础输出语句 不是函数&#xff0c;…

nginx基于IP的多虚拟主机

结合这篇文章一起&#xff1a;nginx虚拟主机-CSDN博客文章浏览阅读63次。虚拟主机指的就是一个独立的站点配置&#xff0c;是nginx默认支持的一个功能&#xff0c;它能够有自己独立的域名&#xff0c;独立的ip&#xff0c;独立的端口配置&#xff0c;能够配置完整的www服务&…

SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心

目录 1. OAuth2.0 简介 2. 代码搭建 2.1 认证中心&#xff08;8080端口&#xff09; 2.2 资源服务中心&#xff08;8081端口&#xff09; 3. 测试结果 1. OAuth2.0 简介 OAuth 2.0&#xff08;开放授权 2.0&#xff09;是一个开放标准&#xff0c;用于授权第三方应用程序…

【Kaggle】泰坦尼克号生存预测 Titanic

文章目录 前言案例背景数据集介绍加载数据集探索性数据分析&#xff08;EDA&#xff09;可视化特征和目标值之间关系缺失值分析 数据预处理数据清洗缺失值处理去除噪声并且规范化文本内容 数据转换 数据划分建模逻辑回归模型决策分类树模型随机森林模型梯度提升树模型 预测LR 完…