数据结构之单链表详解

前言

之前大摆了5天多,没怎么学编程,自昨日起,觉不可如此,痛定思痛,开始继续学习,昨天刷了20多道简单级别的力扣,今天想把链表好好巩固一下,于是乎,把单链表的增删查改搞了出来,还用单链表写了通讯录,等下写完博客在去和双链表缠斗一番,ok,王子公主请看下文

在大刀阔斧地写代码前,我们先稍稍复习一下书面知识。

1. 链表的概念及结构

概念:

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

链表的结构跟火车车厢相似,淡季时车厢会相应减少,旺季时车厢会额外增加几节。将某节车厢去掉/加上,不会影响其他⻋厢,每节车厢都是独⽴存在的。 且每节车厢都有车门。想象⼀下这样的场景,假设每节⻋厢的车门都是锁上的状 态,需要不同的钥匙才能解锁,每次只能携带⼀把钥匙的情况下如何从车头走到车尾?
最简单的做法: 每节⻋厢⾥都放⼀把下⼀节车厢的钥匙。
在链表⾥,每节“⻋厢”是什么样的呢?
与顺序表不同的是, 链表⾥的每节"⻋厢"都是独⽴申请下来的空间,我们称之为“结点/节点”
节点的组成主要有两个部分:当前节点要保存的数据和保存下⼀个节点的地址(指针变量)。
图中指针变量 plist保存的是第⼀个节点的地址,我们称plist此时“指向”第⼀个节点,如果我们希
望plist“指向”第⼆个节点时,只需要修改plist保存的内容为0x0012FFA0。

为什么还需要指针变量来保存下⼀个节点的位置?

链表中每个节点都是独⽴申请的(即需要插⼊数据时才去申请⼀块节点的空间),我们需要通过指针 变量来保存下⼀个节点位置才能从当前节点找到下⼀个节点。
结合前⾯学到的结构体知识,我们可以给出每个节点对应的结构体代码:
假设当前保存的节点为整型
struct SListNode
{
int data; // 节点数据
struct SListNode * next ; // 指针变量⽤保存下⼀个节点的地址
};
当我们想要保存⼀个整型数据时,实际是向操作系统申请了⼀块内存,这个内存不仅要保存整型数
据,也需要保存下⼀个节点的地址(当下⼀个节点为空时保存的地址为空)。
当我们想要从第⼀个节点⾛到最后⼀个节点时,只需要在前⼀个节点拿上下⼀个节点的地址(下⼀个
节点的钥匙)就可以了
补充说明:
  • 1、链式机构在逻辑上是连续的,在物理结构上不⼀定连续
  • 2、节点⼀般是从堆上申请的
  • 3、从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续

2.链表的分类

链表的结构⾮常多样,以下情况组合起来就有8种(2 x 2 x 2)链表结构:
图片来源:比特就业课课件
虽然有这么多的链表的结构,但是我们实际中最常⽤还是两种结构: 单链表 双向带头循环链表
1. ⽆头单向⾮循环链表:结构简单,⼀般不会单独⽤来存数据。实际中更多是作为其他数据结
构的⼦结构,如哈希桶、图的邻接表等等。另外这种结构在笔试⾯试中出现很多。
2. 带头双向循环链表:结构最复杂,⼀般⽤在单独存储数据。实际中使⽤的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使⽤代码实现以后会发现结构会带
来很多优势,实现反⽽简单了,后⾯我们代码实现了就知道了。

3.单链表的增删查改

毕竟只是增删查改,我们只需要写两个文件就够了,一个头文件,一个源文件写函数,

typedef int SLTDataType;
typedef struct SListNode
{
//
}SLTNode;void SLTPrint(SLTNode* phead);//头部插入删除/尾部插入删除
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos);
//销毁链表
void SListDesTroy(SLTNode** pphead);

接着开始实现函数

#include"SLT.h"

SLTNode* creat(SLTDataType x)

{

SLTNode* p = malloc(sizeof(SLTNode));

p->val = x;

p->next = NULL;

return p;

}

void SLTPrint(SLTNode* phead)

{

while (phead)

{

printf("%d ", phead->val);

phead = phead->next;

}

puts("");

}

//尾部插入

void SLTPushBack(SLTNode** pphead, SLTDataType x)

{

assert(pphead);

if (*pphead == NULL)

*pphead = creat(x);

else

{

while ((*pphead)->next)

{

*pphead = (*pphead)->next;

}

(*pphead)->next = creat(x);

}

}

//头部插入

void SLTPushFront(SLTNode** pphead, SLTDataType x)

{

assert(pphead);

if (*pphead == NULL)

if (*pphead == NULL)

*pphead = creat(x);

else

{

SLTNode* new = (*pphead);

*pphead = creat(x);

(*pphead)->next = new;

}

}

//尾部删除

void SLTPopBack(SLTNode** pphead)

{

assert(pphead);

assert(*pphead);

if (((*pphead)->next) == NULL)

*pphead= NULL;

else

{

while ((*pphead)->next->next)

{

(*pphead) = (*pphead)->next;

}

free((*pphead)->next);

(*pphead)->next = NULL;

}

}

//头部删除

void SLTPopFront(SLTNode** pphead)

{

assert(pphead);

assert(*pphead);

SLTNode* new = (*pphead)->next;

free(*pphead);

*pphead = new;

}

//查找

SLTNode* SLTFind(SLTNode* phead, SLTDataType x)

{

while (phead&&phead->val != x)

phead = phead->next;

if (phead == NULL)

{

printf("你要找的内容不存在\n");

return 0;

}

return phead;

}

//在指定位置之前插入数据

void SLTInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x)

{

assert(pphead);

assert(*pphead);

assert(pos);

if ((*pphead) == pos)

{

*pphead = creat(x);

(*pphead)->next = pos;

}

else

{

while ((*pphead)->next != pos)

{

*pphead = (*pphead)->next;

}

SLTNode* new = (*pphead)->next;//不对劲!!!!!!

(*pphead)->next = creat(x);

(*pphead)->next->next = pos;

}

}

//删除pos节点

void SLTErase(SLTNode** pphead, SLTNode* pos)

{

assert(pphead);

assert(*pphead);

if (*pphead == pos)

{

free(pos);

*pphead = NULL;

}

else

{

while ((*pphead)->next != pos)

*pphead = (*pphead)->next;

(*pphead)->next = (*pphead)->next->next;

free(pos);

pos = NULL;

}

}

//在指定位置之后插入数据

void SLTInsertAfter(SLTNode* pos, SLTDataType x)

{

assert(pos);

SLTNode* new = pos->next;

pos->next = creat(x);

pos->next->next = new;

}

//删除pos之后的节点

void SLTEraseAfter(SLTNode* pos)

{

assert(pos);

SLTNode* new = pos->next;

pos->next = pos->next->next;

free(new);

}

//销毁链表

void SListDesTroy(SLTNode** pphead)

{

assert(pphead);

while (*pphead != NULL)

{

SLTNode* p = (*pphead)->next;

free(*pphead);

*pphead = p;

}

}

ok,那么下次单链表的分享就先告一段落了,感谢观看

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

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

相关文章

【数据结构】二叉搜索树的模拟实现

目录 1、概念 2、模拟实现 2.1、查找 2.2、插入 2.3、删除(难点) 3、性能分析 4、完整代码 1、概念 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有…

用通俗易懂的方式讲解:大模型 RAG 高阶技巧,如何实现窗口上下文检索

在本文中,我们将介绍一种提高RAG(Retrieval-Augmented Generation)模型检索效果的高阶技巧,即窗口上下文检索。 我们将首先回顾一下基础RAG的检索流程和存在的问题,然后介绍窗口上下文检索的原理和实现方法&#xff0…

【MATLAB源码-第124期】基于matlab的GFDM系统(64QAM/QPSK调制)在AWGN和PA信道误码率对比。

操作环境: MATLAB 2022a 1、算法描述 广义频分复用(GFDM)是一种先进的信号调制技术,近年来在无线通信领域获得了广泛的关注。GFDM作为一种多载波调制方案,是对经典的正交频分复用(OFDM)技术的…

Stable Diffusion系列(四):提示词规则与使用

文章目录 基础规则高级规则插件使用基于相机镜头增强提示词常用提示词总结奇特提示词珍藏 基础规则 所谓提示词,也就是文生图中的文,由连贯的英语单词或句子组成。其最基础的规则是: 不同提示词之间需要用英文逗号分隔,空格和换…

【极数系列】Flink环境搭建Linux版本 (03)

文章目录 引言01 Linux部署JDK11版本1.下载Linux版本的JDK112.创建目录3.上传并解压4.配置环境变量5.刷新环境变量6.检查jdk安装是否成功 02 Linux部署Flink1.18.0版本1.下载Flink1.18.0版本包2.上传压缩包到服务器3.修改flink-config.yaml配置4.启动服务5.浏览器访问6.停止服务…

【第七天】蓝桥杯备战

题 1、最大距离2、最长递增 1、最大距离 https://www.lanqiao.cn/problems/155/learning/ 解法:暴力遍历 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {public static void main(String[] args) {Scanner scan …

第九节HarmonyOS 常用基础组件16-Blank

1、描述 空白填充组件,在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column/Flex时生效。 2、接口 Blank(min?: number | string) 3、参数 参数名 参数类型 必填 描述 min number|string 否 空白填充组件…

2.3_8 多生产者-多消费者问题

2.3_8 多生产者-多消费者问题 实现思路 semaphore mutex1; //实现互斥访问盘子(缓冲区) semaphore apple0; //盘子中有几个苹果 semaphore orange0; //盘子中有几个橘子 semaphore plate 1; //盘子中还可以放多少个水果dad(){while(1){准备一个苹果;P(plate);P(mutex);把苹果放…

GMS测试BTSfail-CVE-2022-20451

描述: 项目需要过GMS兼容性测试,BTS这块我们环境没有,送检之后出现了一个BTS的Alert,这个是必须要解决的。下面的warning可以不考虑。 这个是patch问题,根据代理提供的pdf文件找到一个id:为A-235098883的补丁&#xf…

数据库管理-第141期 DG PDB - Oracle DB 23c(20240129)

数据库管理141期 2024-01-29 第141期 DG PDB - Oracle DB 23c(20240129)1 概念2 环境说明3 操作3.1 数据库配置3.2 配置tnsname3.3 配置强制日志3.4 DG配置3.5 DG配置建立联系3.6 启用所有DG配置3.7 启用DG PDB3.8 创建源PDB的DG配置3.9 拷贝pdbprod1文件…

UDP通信以及本地套接字

1. UDP 1.1 UDP 通信&#xff1a; UDP服务端创建出来的套接字不是监听套接字&#xff0c;直接就是通信套接字。 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *de…

源码安装nginx并提供服务脚本

一、下载nginx ①官网复制下载链接 ②在Linux中下载 [rootopenEuler2 ~]# wget -c https://nginx.org/download/nginx-1.24.0.tar.gz 二、解压并指定路径 [rootopenEuler2 ~]# tar xf nginx-1.24.0.tar.gz -C /usr/local/src/ 三、安装依赖 dnf install -y gcc gcc-c mak…