数据结构 day4

目录

思维导图:

学习内容:

1. 链表的引入

1.1 顺序表的优缺点

1.1.1 优点

1.1.2 不足

1.1.3 缺点

1.2 链表的概念

1.2.1 链式存储的线性表叫做链表

1.2.2 链表的基础概念

1.3 链表的分类

2. 单向链表

2.1 节点结构体类型

2.2 创建链表 

2.3 申请节点封装数据 

2.4 链表判空 

2.5 头插 

2.6 链表遍历 

2.7 通过位置查找节点 

2.8 任意位置插入元素

2.9 头删 

 2.10 任意位置删除函数

2.11 按值查找返回位置 

2.12 按位置修改 

2.13 按值进行修改函数 

2.14 链表的反转 

2.15 链表的释放

课外作业:


思维导图:


学习内容:

1. 链表的引入

1.1 顺序表的优缺点

1.1.1 优点

        能够直接通过下标进行定位元素,访问效率高,对元素进行查找和修改比较快

1.1.2 不足

        插入和删除元素需要移动大量的元素,效率较低

1.1.3 缺点

        存储数据元素有上限,当达到MAX后,就不能再添加元素了

1.2 链表的概念

1.2.1 链式存储的线性表叫做链表

        链式存储:表示数据元素的存储地址不一定连续

        线性表:数据元素之间存在一对一的关系

1.2.2 链表的基础概念

        1、节点:节点是链表的基本单位,由数据域和指针域组成

        2、数据域:存放数据元素的部分

        3、指针域:存放下一个节点地址的部分

        4、前驱节点:当前节点的上一个节点

        5、后继节点:当前节点的下一个节点

        6、头节点:虚设的一个节点,数据域不存放数据元素,可以存放链表的长度

        7、头指针:指向第一个节点的指针称为头指针

        8、第一个节点:实际存储数据元素的链表上的第一个节点

        注意:头节点的指针域其实就是头指针,也可以单独定义一个指针,指向第一个节点

1.3 链表的分类

        1、单向链表:只能从头节点或第一个节点出发,单向访问其后继节点的链表称为单向链表

        2、双向链表:从头部出发,既可以访问前驱节点,也可以访问后继节点

        3、循环链表:首尾相接的链表称为循环链表

2. 单向链表

2.1 节点结构体类型

        1> 头节点和普通节点数据域可以合到一起,使用一格共用体表示

        2> 指针域都是指向普通节点的地址

//定义数据类型
typedef int datatype;//定义结点类型
typedef struct Node
{union{int len;    //头结点数据域datatype data;  //普通结点数据域};struct Node *next;   //指针域
};

2.2 创建链表 

        1> 在堆区申请一格头节点的空间,就创建了一个链表

        2> 需要对头节点的数据域初始化链表长度,指针域初始化NULL

//创建链表
NodePtr list_create()
{//只需要在堆区申请一个头结点NodePtr L = (NodePtr)malloc(sizeof(Node));if(NULL == L){printf("创建失败\n");return NULL;}//程序执行至此,说明头结点创建结束L->len = 0;    //表示链表长度为0L->next = NULL;      ///防止野指针printf("链表创建成功\n");return L;
}

2.3 申请节点封装数据 

        1> 需要将要封装的数据当做函数的参数进行传递

        2> 同样在堆区申请节点,就传入的数据放入数据域

//申请结点封装数据函数
NodePtr apply_node(datatype e)
{//在堆区申请一个结点的大小NodePtr p = (NodePtr)malloc(sizeof(Node));if(NULL == p){printf("结点申请失败\n");return NULL;}//给结点内容赋值p->data = e;          //数据域赋值p->next = NULL;        //指针域return p;
}

2.4 链表判空 

        只需要判断头节点的指针域中是否为空即可

//链表判空
int list_empty(NodePtr L)
{return L->next == NULL;
}

2.5 头插 

        1> 表示将新插入的节点放入第一个节点中

        2> 插入数据时,不能先将前面节点与后面节点先断开。一定要从新节点出发,指向后面的节点,然后将前驱节点指向字节

//头插
int list_insert_head(NodePtr L, datatype e)
{//判断逻辑if(NULL==L){printf("链表不合法\n");return -1;}//申请结点封装数据NodePtr p = apply_node(e);if(NULL==p){return -1;}//头插逻辑p->next = L->next;L->next = p;//表的变化L->len ++;printf("头插成功\n");return 0;
}

2.6 链表遍历 

        需要使用一个遍历指针,将每一个节点进行遍历一遍,如果该指针指向的节点不为空,就访问其数据域,向后偏移

//链表遍历函数
int list_show(NodePtr L)
{//判断逻辑if(NULL==L || list_empty(L)){printf("遍历失败\n");return -1;}printf("链表中的元素分别是:");//遍历逻辑NodePtr q = L->next;   //定义遍历指针从第一个结点出发while(q != NULL){//输出数据域printf("%d\t", q->data);q = q->next;    //指针向后偏移一个}
}

2.7 通过位置查找节点 

        1> 参数:链表、位置

        2> 返回值:对应节点的地址

//通过位置查找结点
NodePtr list_search_pos(NodePtr L, int pos)
{//判断逻辑if(NULL==L || list_empty(L) || pos<0 || pos>L->len){printf("查找失败\n");return NULL;}//查找逻辑//定义遍历指针从头结点出发NodePtr q = L;for(int i=0; i<pos; i++){q = q->next;}return q;     //将找到的结点地址返回
}

2.8 任意位置插入元素

        1> 参数:链表、位置、要插入的元素

        2> 返回值:int

        3> 注意:必须找到要插入位置的节点的前驱节点,将前驱节点当作头节点,进行头插操作

//任意位置插入
int list_insert_pos(NodePtr L, int pos, datatype e)
{//判断逻辑if(NULL==L || pos<1 || pos>L->len+1){printf("插入失败\n");return -1;}//申请结点封装数据NodePtr p = apply_node(e);if(NULL==p){return -1;}//调用函数查找前驱结点NodePtr q = list_search_pos(L, pos-1);//插入逻辑p->next = q->next;q->next = p;//表的变化L->len++;printf("插入成功\n");return 0;
}

2.9 头删 

        1> 参数:链表

        2> 返回值:int

        3> 注意:需要将要删除的节点先标记一下,头节点的指针,指向第二个节点后,将标记的节点释放

//链表头删
int list_delete_head(NodePtr L)
{//判断逻辑if(NULL==L || list_empty(L)){printf("删除失败\n");return -1;}//删除三部曲NodePtr p = L->next;    //标记L->next = p->next;  //L->next->next  孤立free(p);            //释放p = NULL;//表长变化L->len--;printf("头删成功\n");return 0;
}

 2.10 任意位置删除函数

        1> 参数:链表、要删除的位置

        2> 返回值:int

        3> 注意:需要找到要删除的节点的前驱节点,将其当作头节点,进行头删逻辑

//链表任意位置删除
int list_delete_pos(NodePtr L, int pos)
{//判断逻辑if(NULL==L || list_empty(L) || pos<1 || pos>L->len){printf("删除失败\n");return -1;}//找到前驱结点NodePtr q = list_search_pos(L, pos-1);//删除逻辑NodePtr p = q->next;           //标记q->next = q->next->next;   //p->next 孤立free(p);                   //释放p = NULL;//表的变化L->len--;printf("删除成功\n");return 0;
}

2.11 按值查找返回位置 

        1> 参数:链表、要查找的值

        2> 返回值:元素在链表中的位置

//链表按值查找返回位置
int list_search_value(NodePtr L, datatype e)
{//判断逻辑if(NULL==L || list_empty(L)){printf("查找失败\n");return -1;}//查找逻辑//定义遍历指针从第一个结点出发NodePtr q = L->next;for(int index=1; index<=L->len; index++){//判断当前结点的值是否为要找的数据if(q->data == e){return index;}q = q->next;     //继续向后遍历}//程序执行至此,表示没找到printf("没找到\n");return -1;
}

2.12 按位置修改 

        1> 参数:链表、要修改的元素位置、要被更新的值

        2> 返回值:int

        3> 注意:先通过位置,找到对应的元素,更改该元素中的内容即可

//链表按位置进行修改
int list_update_pos(NodePtr L, int pos, datatype e)
{//判断逻辑if(NULL==L || list_empty(L) || pos<1 || pos>L->len){printf("修改失败\n");return -1;}//按位置查找逻辑NodePtr p = list_search_pos(L, pos);//修改逻辑p->data = e;printf("修改成功\n");return 0;
}

2.13 按值进行修改函数 

        1> 参数:链表、旧值、新值

        2> 返回值:int

        3> 思路:先通过旧值找到位置,通过位置进行修改

//按值进行修改
int list_update_value(NodePtr L, datatype old_e, datatype new_e)
{//判断逻辑if(NULL==L || list_empty(L)){printf("修改失败\n");return -1;}//按值查找位置int res = list_search_value(L, old_e);if(res == -1){printf("没有要修改的值\n");return -1;}//按位置修改list_update_pos(L, res, new_e);printf("修改成功\n");return 0;
}

2.14 链表的反转 

        1> 参数:链表

        2> 返回值:int

        3> 注意:在该操作中,没有节点被删除,也没有节点被释放

//将链表进行翻转
void list_reverse(NodePtr L)
{//判断逻辑if(NULL==L || L->len<=1){printf("翻转失败\n");return ;}//翻转逻辑NodePtr H = L->next;   //将链表元素进行托付L->next = NULL;        //自己白手起家NodePtr p = NULL;         //结点的搬运工while(H != NULL){p = H;      //搬运第一个结点H = H->next;     //头指针后移//将p以头插的方式放入L中p->next = L->next;L->next = p;}printf("翻转成功\n");}

2.15 链表的释放

         1> 参数:链表

        2> 返回值:无

        3> 注意:需要先将所有的节点内存全部释放后,再将头节点释放

//释放链表
void list_destroy(NodePtr L)
{//判断逻辑if(NULL == L){return;}//将所有结点进行释放while(!list_empty(L)){//头删list_delete_head(L);}//释放头结点free(L);L = NULL;printf("释放成功\n");
}


课外作业:

1.链表的排序

解析:

//排序
void list_sort(NodePtr L)
{if(NULL == L || list_empty(L)){printf("排序失败\n");return ;}for (int i = 0; i < L->len; i++){NodePtr q=L->next;NodePtr q1 = q->next;while(q1 != NULL){if(q->data > q1->data){datatype temp = q->data;q->data = q1->data;q1->data  =temp;}q=q->next;            //指针向后偏移一个q1= q1->next;}}printf("排序成功\n");list_print(L);
}

2.链表的反转(递归实现)

解析:

3. 链表去重

解析:

void list_rep(NodePtr L)
{if(NULL == L || L->len<=1){printf("去重失败\n");return ;}NodePtr q = L;while(q->next != NULL){if(q->data == q->next->data){NodePtr temp = q->next;q->next = temp->next;free(temp);}else{q=q->next;}}printf("去重成功\n");list_print(L);
}

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

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

相关文章

pikachu之暴力破解

1基于表单的暴力破解 随便输入然后抓包 选中添加账号密码 添加分别添加payload1&#xff0c;2&#xff0c;的字典 开始攻击 2验证码绕过on server 和基于表单的暴力破解相比&#xff0c;多了一个验证码功能 这个验证码是前端的验证码&#xff08;和前面那个一样选中添加账号密码…

Java小技能:多级组织机构排序并返回树结构(包含每个层级的子节点和业务数据集合)

文章目录 引言I 实体定义1.1 部门1.2 用户组织机构中间表1.3 树状DTOII 抽取组织机构排序方法2.1 树状排序方法2.2 案例III 查询条件构建3.1 根据部门进行权限控制3.2 注入风险引言 需求: 根据组织机构进行数据授权控制,例如控制船舶、船舶设备、摄像头、港区查看权限。 一…

kettle从入门到精通 第七十六课 ETL之kettle kettle连接hive教程

1、群里有小伙伴询问kettle连接hive的demo&#xff0c;今天抽点时间整理下。其实kettle连接hive和连接mysql数据库也是一样的。 1&#xff09;kettle中的lib目录下放hive驱动jar&#xff0c;这里我使用的是kyuubi-hive-jdbc-shaded-1.9.0.jar。 2&#xff09;设置hive连接参数…

pytorch学习(九)激活函数

1.pytorch常用激活函数如下&#xff1a; #ReLU激活函数 #Leaky ReLU激活函数 #Sigmoid激活函数 #Tanh激活函数 #Softmax激活函数 #Softplus2.代码 import torch.nn as nn import torch import numpy from torch.utils.tensorboard import SummaryWriterwriter SummaryWriter…

ModuleNotFoundError: No module named ‘lime‘,lime。 安装 LIME库

LIME LIME 的作用安装 LIME示例代码详细解释 总结 LIME&#xff08;Local Interpretable Model-agnostic Explanations&#xff0c;局部可解释不可知模型&#xff09;是一个Python库&#xff0c;用于解释机器学习模型的预测结果。它通过构建一个简单的、本地的可解释模型来近似…

【BUG】已解决:ModuleNotFoundError: No module named ‘torch‘

已解决&#xff1a;ModuleNotFoundError: No module named ‘torch‘ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市…

Unity UGUI 之EventSystem

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 1.EventSystem是什么&#xff1f; 有需要请查看手册&#xff1a;Unity - 手册&#xff1…

2024.7.19最新详细的VMware17.0.0安装

VM官网VMware - Delivering a Digital Foundation For Businesses。现在官网无法下载&#xff0c;点击会跳转到https://access.broadcom.com/default/ui/v1/signin/ 要注册一个账号&#xff1a; 注册登录以后&#xff0c;点击Please select your identity provider. - Support …

昇思25天学习打卡营第2天 | 快速入门

在快速发展的人工智能领域&#xff0c;深度学习已经成为数据分析和模式识别的核心技术。作为一名深度学习初学者&#xff0c;我有幸通过MindSpore平台进行了实战演练&#xff0c;从数据预处理到模型训练与测试&#xff0c;再到模型保存与加载&#xff0c;经历了一次完整的深度学…

基于SpringBoot+Vue的校园台球厅设备管理系统(带1w+文档)

基于SpringBootVue的校园台球厅设备管理系统(带1w文档) 基于SpringBootVue的校园台球厅设备管理系统(带1w文档) 本次设计任务是要设计一个校园台球厅人员与设备管理系统&#xff0c;这个系统能够满足校园台球厅人员与设备的管理及用户的校园台球厅人员与设备管理功能。系统的主…

彻底卸载360安全卫士的方法

法一&#xff1a; 按下WindowsR键&#xff0c;并输入msconfig, 在“引导”选项卡中选择“安全引导”&#xff0c;并重新启动进入安全模式。此时&#xff0c;重复第一种方法“应用和功能”-“360安全卫士”-“卸载”&#xff0c;在弹出的对话框中残忍的拒绝它的各种令人发指的无…

go-微服务的设计概括

一、微服务到底是什么&#xff1f; 初学者很容易把微服务和分布式混为一谈&#xff0c;但其实二者之间存在非常大的差异&#xff0c;我个人认为主要有以下几点&#xff1a; 分布式主要是一种技术手段&#xff0c;用来保证多个相同的进程能够共同工作而不出错。采用各种复杂的…

基于Ubuntu2310搭建openstack高可用集群B版

openstack-ha 环境初始化安装haproxy安装keepalived数据库集群高可用rabbitmq集群高可用memcache集群配置 keystone高可用glance高可用placement高可用nova高可用neutron高可用horizon高可用 本实验使用两台节点master和node配置haproxy高可用&#xff0c;keepliaved配置主备抢…

IntelliJ IDEA 直接在软件中更新为最新版

当我们的 IDEA 工具许久没有更新&#xff0c;已经拖了好几个版本&#xff0c;想跨大版本更新&#xff0c;比如从2020.2.1 -> 2023.x.x 此时&#xff0c;我们菜单栏点击 Help -> Check for Updates… &#xff0c;右下角会有提示更新&#xff0c;如下图&#xff1a; 点…

go 实现websocket以及详细设计流程过程,确保通俗易懂

websocket简介&#xff1a; WebSocket 是一种网络传输协议&#xff0c;可在单个 TCP 连接上进行全双工通信&#xff0c;位于 OSI 模型的应用层。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455&#xff0c;后由 RFC 7936 补充规范。 WebSocket 使得客户端和服务器之间的数…

Python PDF Magic:合并和拆分随心所欲

大家好&#xff01;小编今天要为大家带来一篇关于Python操作PDF的秘籍——无论是要将PDF合并成一份整体&#xff0c;还是将一个庞大的PDF文件拆分成多个小伙伴&#xff0c;都轻松hold住&#xff01;你准备好了吗&#xff1f;让我们开始这场奇妙的PDF操作之旅吧&#xff01; 准…

机械学习—零基础学习日志(高数06——函数特性)

零基础为了学人工智能&#xff0c;真的开始复习高数 函数的性质&#xff0c;开始新的学习&#xff01; 有界性&#xff1a; 解法放这里&#xff1a; 证明有界&#xff0c;其实内部的包含知识点很多。第一&#xff0c;如果有界&#xff0c;你需要证明函数在一定区间内&#xff…

《Techporters架构搭建》-Day02 集成Mybatis-plus

集成Mybatis-plus Mybatis-plus集成Mybatis-plus步骤小结 Mybatis-plus Mybatis-plus官网 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它引入了一些新的特性&…

【探索Linux】P.40(传输层 —— TCP滑动窗口 | 快重传 | 流量控制 )

阅读导航 引言一、TCP滑动窗口1. 为什么要用滑动窗口&#xff08;1&#xff09;逐个确认&#xff08;2&#xff09;优化逐个确认&#xff08;滑动窗口&#xff09; 2. TCP滑动窗口的工作原理 二、快重传的引入三、快速重传详细介绍1. 机制原理2. 触发条件3. 操作步骤4. 与超时重…

如何处理AI模型中的“Gradient Vanishing”错误:优化训练技巧

如何处理AI模型中的“Gradient Vanishing”错误&#xff1a;优化训练技巧 &#x1f311; 如何处理AI模型中的“Gradient Vanishing”错误&#xff1a;优化训练技巧 &#x1f311;摘要引言“Gradient Vanishing”问题的成因分析 &#x1f914;1. 激活函数的选择2. 网络层数过深3…