单链表详解

💓博主个人主页:不是笨小孩👀
⏩专栏分类:数据结构与算法👀
🚚代码仓库:笨小孩的代码库👀
⏩社区:不是笨小孩👀
🌹欢迎大家三连关注,一起学习,一起进步!!💓

单链表

  • 链表的概念及结构
    • 概念
    • 结构
  • 单链表的实现
    • 结构
    • 它的接口有哪些呢?
      • 申请节点
      • 打印链表
      • 尾插
      • 头插
      • 尾删
      • 头删
      • 查找
      • 在pos位置之后插入x
      • 在pos位置前面插入
      • 删除pos之后的值
      • 删除pos位置的值
      • 销毁链表

在这里插入图片描述

链表的概念及结构

概念

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

结构

在逻辑上链表应该是这样子的:
在这里插入图片描述
在现实中是这样子的:

在这里插入图片描述
注意:

链表在逻辑上时连续的,但是在物理上不一定连续。
现实中的节点一般是从堆上申请出来的 。
从堆上申请的空间,可能是连续的也可能是不连续的。

单链表的实现

结构

单链表结构中有两个数据,一个是存储数据的,还有一个指针指向下一个节点。

typedef int SLTDateType;typedef struct SListNode
{SLTDateType date;struct SListNode* next;
}SLTNode;

它的接口有哪些呢?

// 动态申请一个节点
SLTNode* BuySListNode(SLTDateType x);// 单链表打印
void SListPrint(SLTNode* plist);// 单链表尾插
void SListPushBack(SLTNode** pplist, SLTDateType x);// 单链表的头插
void SListPushFront(SLTNode** pplist, SLTDateType x);// 单链表的尾删
void SListPopBack(SLTNode** pplist);// 单链表头删
void SListPopFront(SLTNode** pplist);// 单链表查找
// 找到返回这个节点的地址。找不到返回NULL
SLTNode* SListFind(SLTNode* plist, SLTDateType x);// 单链表在pos位置之后插入x
void SListInsertAfter(SLTNode* pos, SLTDateType x);// 单链表删除pos位置之后的值
void SListEraseAfter(SLTNode* pos);// 单链表的销毁
void SListDestroy(SLTNode* plist);//在pos前插入
void SListInsert(SLTNode** pplist,SLTNode* pos, SLTDateType x);// 删除pos节点
void SListErase(SLTNode** pplist, SLTNode* pos);

申请节点

我们要添加数据,难免要频繁的开辟节点,所以我们分装以个函数专门来开辟节点。

// 动态申请一个节点
SLTNode* BuySListNode(SLTDateType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");//开辟失败结束掉程序exit(-1);}newnode->date = x;newnode->next = NULL;return newnode;
}

打印链表

打印链表比较简单,只需要遍历一遍链表即可。

void SListPrint(SLTNode* plist)
{SLTNode* cur = plist;while (cur){printf("%d->", cur->date);cur = cur->next;}printf("NULL\n");
}

尾插

尾插时链表可能为空,所以这时就要把将头指向开辟的节点,这是需要改变头,想要改变一级指针,所以就要传一级指针的地址,这时就需要用一个二级指针来接收,如果链表不为空,我们正常尾插就可以,我们需要先找到尾节点,然后就为节点的next指向newnode即可。

// 单链表尾插
void SListPushBack(SLTNode** pplist, SLTDateType x)
{
// 断言pplist一定不为空,为空时程序异常,终止程序assert(pplist);SLTNode* newnode = BuySListNode(x);if (*pplist == NULL){//链表为空*pplist = newnode;}else{SLTNode* cur = *pplist;//找尾节点while (cur->next){cur = cur->next;}cur->next = newnode;}
}

头插

头插同样需要改变头结点,所以还是需要二级指针,头插只需要将newnode的next指向原链表的头,然后将原链表的头指向newnode就可以了。

void SListPushFront(SLTNode** pplist, SLTDateType x)
{
// 断言pplist一定不为空,为空时程序异常,终止程序assert(pplist);SLTNode* newnode = BuySListNode(x);newnode->next = *pplist;(*pplist) = newnode;
}

尾删

尾删只剩一个节点时同样的需要改变头指针,这时free掉头结点,将其置NULL即可。正常情况下,我们只需要找到尾节点的前一个,然后释放掉尾节点,然后把前一个的next置NULL即可。

// 单链表的尾删
void SListPopBack(SLTNode** pplist)
{
// 断言pplist一定不为空,为空时程序异常,终止程序assert(pplist);
//断言链表为空就不要删了assert(*pplist);if ((*pplist)->next == NULL){free(*pplist);*pplist = NULL;}else{SLTNode* tail = *pplist;// 至少有两个节点所以tail->next一定不为NULLwhile (tail->next->next){tail = tail->next;}free(tail->next);tail->next = NULL;}
}

头删

头删一定需要改变头结点,所以同样需要二级指针,我们需要保存头结点的next,让然后释放掉头结点,将头结点重新指向保存下来的next即可。

// 单链表头删
void SListPopFront(SLTNode** pplist)
{
// 断言pplist一定不为空,为空时程序异常,终止程序assert(pplist);
//断言链表为空就不要删了assert(*pplist);//*pplist一定不为NULLSLTNode* cur = (*pplist)->next;free(*pplist);*pplist = cur;}

查找

查找就很简单了,我们只需要遍历一遍链表即可。

// 单链表查找
SLTNode* SListFind(SLTNode* plist, SLTDateType x)
{
//断言链表为空就不要查了assert(plist);SLTNode* cur = plist;while (cur){if (cur->date == x){return cur;}cur = cur->next;}return NULL;
}

在pos位置之后插入x

只需要将newnode的next指向pos的next,然后将pos的next指向newnode即可。

// 单链表在pos位置之后插入x
void SListInsertAfter(SLTNode* pos, SLTDateType x)
{assert(pos);SLTNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;
}

在pos位置前面插入

如果是一个节点间的话接相当于头插,我们可以复用上面头插的代码,正常情况下我们需要遍历找到pos的前一个位置,将newnode的next指向pos,再把该节点指向newnode即可。

void SListInsert(SLTNode** pplist, SLTNode* pos, SLTDateType x)
{assert(pplist);if (pos == *pplist){SListPushFront(pplist, x);}else{SLTNode* cur = *pplist;while (cur->next != pos){cur = cur->next;}SLTNode* newnode = BuySListNode(x);newnode->next = pos;cur->next = newnode;}
}

删除pos之后的值

不能删除最后一个节点,其他情况我们可以直接释放掉pos的next,将pos的next指向下一个即可。

// 单链表删除pos位置之后的值
void SListEraseAfter(SLTNode* pos)
{assert(pos);assert(pos->next);SLTNode* cur = pos->next;pos->next = cur->next;free(cur);cur = NULL;
}

删除pos位置的值

我们需要遍历找pos的前一个位置,然后将pos的前一个位置的next指向pos的next,然后释放掉pos即可,但是如果pos是头结点,我们这样处理不了,我们可以单独处理,相当头删。

void SListErase(SLTNode** pplist, SLTNode* pos)
{assert(pplist);if (pos == *pplist){SListPopFront(pplist);}else{SLTNode* cur = *pplist;while (cur->next != pos){cur = cur->next;}cur->next = pos->next;free(pos);}
}

销毁链表

销毁只需要遍历释放即可。

// 单链表的销毁
void SListDestroy(SLTNode* plist)
{assert(plist);SLTNode* cur = plist;while (cur){SLTNode* pur = cur;cur = cur->next;free(pur);}
}

到这里对于单链表的增删查改已经讲的差不多了,我们的查找可以充当改,找到那个节点,直接修改date即可。

今天的分享就到这里结束了,感谢大家的支持和关注。

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

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

相关文章

Mac 安装启动RabbitMq

使用HomeBrew安装 未安装的请参照我的这篇Mac安装HomeBrew文章 安装 执行命令 brew install rabbitmq启动方式 brew services start rabbitmq端口说明 端口用处5672RabbitMQ通讯端口,也就是连接使用的端口15672RabbbitMQ管理界面端口,需要开启Manage…

web自动化测试-PageObject 设计模式

为 UI 页面写测试用例时(比如 web 页面,移动端页面),测试用例会存在大量元素和操作细节。当 UI 变化时,测试用例也要跟着变化, PageObject 很好的解决了这个问题。 使用 UI 自动化测试工具时(包…

Zebec Card 将在亚洲、拉美等地区推出,生态全球化加速

随着以Visa、特斯拉、BNY Mellon、BlackRock、Mastercard、Gucci等为代表的传统商业机构巨头,以及萨尔瓦多、中非共和国等为代表的国家不断的向加密货币领域布局,越来越多的投资者开始以新的眼光来看待加密货币,仅在2022年,加密货…

如何学好Java并调整学习过程中的心态:学习之路的秘诀

文章目录 第一步:建立坚实的基础实例分析:选择合适的学习路径 第二步:选择合适的学习资源实例分析:参与编程社区 第三步:动手实践实例分析:开发个人项目 调整学习过程中的心态1. 不怕失败2. 持续学习3. 寻求…

Unity自定义后处理——Tonemapping色调映射

大家好,我是阿赵。   继续介绍屏幕后处理,这一期介绍一下Tonemapping色调映射 一、Tone Mapping的介绍 Tone Mapping色调映射,是一种颜色的映射关系处理,简单一点说,一般是从原始色调(通常是高动态范围&…

SpringBoot 如何进行 统一异常处理

在Spring Boot中,可以通过自定义异常处理器来实现统一异常处理。异常处理器能够捕获应用程序中抛出的各种异常,并提供相应的错误处理和响应。 Spring Boot提供了ControllerAdvice注解,它可以将一个类标记为全局异常处理器。全局异常处理器能…

【动态规划】子数组系列

文章目录 动态规划(子数组系列)1. 最大子数组和2. 环形子数组的最大和3. 乘积最大子数组4. 乘积为正的最长子数组的长度5. 等差数列划分6. 最长湍流子数组7. 单词拆分8. 环形字符串中的唯一的子字符串 动态规划(子数组系列) 1. 最…

算法与数据结构(四)--排序算法

一.冒泡排序 原理图: 实现代码: /* 冒泡排序或者是沉底排序 *//* int arr[]: 排序目标数组,这里元素类型以整型为例; int len: 元素个数 */ void bubbleSort (elemType arr[], int len) {//为什么外循环小于len-1次?//考虑临界情况&#xf…

Neo4j 集群和负载均衡

Neo4j 集群和负载均衡 Neo4j是当前最流行的开源图DB。刚好读到了Neo4j的集群和负载均衡策略,记录一下。 1 集群 Neo4j 集群使用主从复制实现高可用性和水平读扩展。 1.1 复制 集群的写入都通过主节点协调完成的,数据先写入主机,再同步到…

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测

振弦采集仪及在线监测系统完整链条的岩土工程隧道安全监测 近年来,随着城市化的不断推进和基础设施建设的不断发展,隧道建设也日益成为城市交通发展的必需品。然而,隧道建设中存在着一定的安全隐患,如地质灾害、地下水涌流等&…

springboot第32集:redis系统-android系统-Nacos Server

Error parsing HTTP request header HTTP method names must be tokens 检查发送HTTP请求的客户端代码,确保方法名中不包含非法字符。通常情况下,HTTP请求的方法名应该是简单的标识符,例如"GET"、"POST"、"PUT"…

《TCP IP网络编程》第十二章

第 12 章 I/O 复用 12.1 基于 I/O 复用的服务器端 多进程服务端的缺点和解决方法: 为了构建并发服务器,只要有客户端连接请求就会创建新进程。这的确是实际操作中采用的一种方案,但并非十全十美,因为创建进程要付出很大的代价。…

免费商用 Meta 发布开源大语言模型 Llama 2

Meta 和微软深度合作,正式推出下一代开源大语言模型 Llama 2,并宣布免费提供给研究和商业使用。 Llama 2 论文地址:Llama 2: Open Foundation and Fine-Tuned Chat Models 据介绍,相比于 Llama 1,Llama 2 的训练数据多…

Tensorflow学习

一、处理数据的结构 案例代码如下: import tensorflow.compat.v1 as tf tf.disable_v2_behavior() import numpy as np# create data x_data np.random.rand(100).astype(np.float32) y_data x_data*0.1 0.3# 创建结构(一维结构) Weights tf.Variable(tf.random.uniform(…

C++模板

目录 函数模板隐式实例化显式实例化 类模板 下面是多种类型的交换函数 void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left right;right temp; } void Swap(ch…

Redis 哨兵 (sentinel)

是什么 官网理论:https://redis.io/docs/management/sentinel/ 吹哨人巡查监控后台 master 主机是否故障,如果故障了根据投票数自动将某一个从库转换为新主库,继续对外服务。 作用:无人值守运维 哨兵的作用: 1…

Pytorch深度学习-----神经网络的卷积操作

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用(ToTensor,Normalize,Resize ,Co…

【状态估计】基于UKF、AUKF的电力系统负荷存在突变时的三相状态估计研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

SentencePiece android ndk编译

LLaMa等LLM语言模型一般使用SentencePiece tokenizer,在端侧部署需要编译和使用其c版本。 在安卓平台使用NDK编译 CMakeLists.txt需要进行一些修改: src/CMakeLists.txt如下位置加上log依赖,否则提示android log相关符号不存在。 此外&…

RNN架构解析——LSTM模型

目录 LSTMLSTM内部结构图 Bi-LSTM实现 优点和缺点 LSTM LSTM内部结构图 Bi-LSTM 实现 优点和缺点