数据结构之单链表详解

前言

之前大摆了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.mzph.cn/news/654788.shtml

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

相关文章

基础算法之Huffman编码

// Type your code here, or load an example. #include<iostream> #include<string> #include<queue> #include <unordered_map> #include <vector>using namespace std;//树节点结构 struct Node {char ch;int freq;Node *left;Node *right;No…

数据结构3、基于栈的后缀算术表达式求值

1 题目描述 图1 中缀表达式转化为后缀表达式题目描述 图2 基于栈的后缀算术表达式求值题目描述 2 题目解读 借助一个运算符栈&#xff0c;可将中缀表达式转化为后缀表达式&#xff1b;借助一个运算数栈&#xff0c;可对后缀表达式求值。借助一个运算符栈和一个运算数栈&#xf…

Java基础数据结构之哈希表

概念 顺序结构以及平衡树 中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在 查找一个元素时&#xff0c;必须要经过关键 码的多次比较 。 顺序查找时间复杂度为 O(N) &#xff0c;平衡树中为树的高度&#xff0c;即 O( log2N ) &#xff0c;搜索的效…

防火墙用户认证、NAT、策略路由、DNS透明代理以及双机热备笔记

用户认证 防火墙管理员登录认证 --- 检验身份的合法性&#xff0c;划分身份权限 用户认证 --- 上网行为管理的一部分 用户&#xff0c;行为&#xff0c;流量 --- 上网行为管理三要素 用户认证的分类 上网用户认证 --- 三层认证 --- 所有的跨网段的通信都可以属于上网行为。…

【Web前端实操19】商城官网_分析与顶部广告

本次实操主要是借用小米之前的网站来进行参考&#xff0c;达成网站静态页面开发的目的&#xff0c;而新学者想要一次性直接开发整个网站&#xff0c;肯定会很懵圈&#xff0c;因此&#xff0c;这个商城官网我会一部分一部分地进行拆分来写&#xff0c;最后合成整个界面。 本次…

国企重组整合后,如何严把“选人用人”关?

三年国企改革之后&#xff0c;新一轮国企改革明确重组方向&#xff0c;强调将“战略性重组和专业化整合”作为深化供给侧结构性改革从而建设世界一流企业的重要抓手&#xff0c;推动了国有资源的高效运转流动。在很多企业兼并、重组后&#xff0c;成立了新的集团性公司&#xf…

Mysql查询数据

1 基本查询语句 MySQL从数据表中查询数据的基本语句为SELECT语句。SELECT语句的基本格式是&#xff1a; 2 单表查询 2.1 查询所有字段 SELECT * FROM 表名; 2.2 在SELECT语句中指定所有字段 SELECT f_id, s_id ,f_name, f_price FROM fruits; 2.3 查询单个字段 SELECT 列名FR…

nginx部署前端(vue)项目及配置修改

目录 一、前端应用打包 二、部署前端应用 1、上传前端文件夹 2、修改nginx配置文件 3、重启nginx 三、查看效果 nginx安装参考&#xff1a;linux安装nginx-CSDN博客 一、前端应用打包 打包命令 npm run build 打包成功如下&#xff0c;会在项目路径下生成dist文件夹 二…

Windows Server 2003 Web服务器搭建

系列文章目录 目录 系列文章目录 前言 一、Web服务器是什么&#xff1f; 二、配置服务器 1.实验环境搭建 2.服务器搭建 1)控制面板中找到增加或删除程序打开 2)点击增加程序 3)安装Web服务器 4)查看安装是否成功 5)打开Internet信息服务(IIS)管理器,进行配置 6)找…

【开源之美】:cppcheck

一、项目链接 https://github.com/danmar/cppcheck/tree/main 二、效果示例

图像复原的天花板在哪里?SUPIR:开创性结合文本引导先验和模型规模扩大

SUPIR&#xff08;Scaling-UP Image Restoration&#xff09;&#xff0c;这是一种开创性的图像复原方法&#xff0c;利用生成先验和模型扩大规模的力量。通过利用多模态技术和先进的生成先验&#xff0c;SUPIR在智能和逼真的图像复原方面取得了重大进展。作为SUPIR中的关键催化…

如何配置MacLinuxWindows环境变量

这里写目录标题 什么是环境变量什么是PATH为什么要配置环境变量 如何配置环境变量环境变量有哪些环境变量加载顺序环境变量加载详解 配置参考方法一&#xff1a; export PATHLinux环境变量配置方法二&#xff1a;vim ~/.bashrcLinux环境变量配置方法三&#xff1a;vim ~/.bash_…

go语言基础之泛型

1.泛型 泛型是一种独立于所使用的特定类型的编写代码的方法。使用泛型可以编写出适用于一组类型中的任何一种的函数和类型。 1.1 为什么需要泛型 func reverse(s []int) []int {l : len(s)r : make([]int, l)for i, e : range s {r[l-i-1] e}return r }fmt.Println(reverse…

红外热成像仪定制_热成像仪/红外夜视仪开发方案

红外热成像技术是一种利用红外热成像仪将物体发出的不可见红外辐射能量转换成可见的温度场图像的技术&#xff0c;通过不同颜色来表示不同温度。这项技术的应用领域非常广泛&#xff0c;从电路维修到暖通检测再到汽车故障排查等各个领域都有着重要的作用。 红外热成像仪的解决方…

SpringBoot项目实现热部署的配置方法

SpringBoot项目实现热部署的配置方法 1、什么是热部署&#xff1f; 热部署&#xff0c;就是在应用正在运行的时候升级软件&#xff0c;却不需要重新启动应用。 2、什么是SpringBoot热部署&#xff1f; SpringBoot热部署就是在项目正在运行的时候修改代码, 却不需要重新启动…

PCB的通孔,盲孔,埋孔

通孔&#xff1a;双层板从顶层到底层的打通&#xff0c;这样电流就能够从顶层到底层 盲孔&#xff1a;因为看不到底&#xff0c;像一口井一样&#xff0c;只能打到中间&#xff0c;里面灌上铜&#xff0c;我们可以从第一层切换到第二层&#xff0c;第三层等等&#xff0c;盲孔…

在Windows上安装与配置Apache服务并结合内网穿透工具实现公网远程访问本地内网服务

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

[React源码解析] Fiber

在React15及以前, Reconciler采用递归的方式创建虚拟Dom, 但是递归过程不可以中断, 如果组件的层级比较深的话, 递归会占用线程很多时间, 那么会造成卡顿。 为了解决这个问题, React16将递归的无法中断的更新重构为异步的可中断更新, Fiber架构诞生。 文章目录 1.Fiber的结构2…

【blender烘焙】法线烘焙出现大面积结构丢失怎么办?blender烘焙vs八猴烘焙

用dcc烘焙法线是很常用的减面优化手段&#xff0c;很多建模的dcc自己也内置的烘焙的功能&#xff0c;像我自己在工作流中也偶尔用blender的烘焙做一下材质的整合优化&#xff0c;在质量要求不高的时候还算凑合可用。 问题描述 在前期的文章中飞燕2号建模&#xff0c;我就遇到…

数据防泄密方案公司(dlp数据防泄密厂商排名)

在当今数字化时代&#xff0c;数据已经成为了企业最重要的资产之一。然而&#xff0c;随着企业信息化的不断深入&#xff0c;数据泄露的风险也越来越大。为了保护企业的核心数据&#xff0c;越来越多的企业开始重视数据防泄密工作&#xff0c;并寻求专业的数据防泄密方案提供商…