当前位置: 首页 > article >正文

【数据结构】顺序表和链表详解(下)

前言:上期我们从顺序表开始讲到了单链表的概念,分类,和实现,而这期我们来将相较于单链表没那么常用的双向链表。

在这里插入图片描述

文章目录

  • 一、双向链表
  • 二,双向链表的实现
    • 一,增
      • 1,头插
      • 2,尾插
      • 3,在指定位置后插入
    • 二,删
      • 1,头删
      • 2,尾删
      • 3,删除pos位置的节点
    • 三,查
    • 四,链表的销毁
    • 五,测试代码
    • 六,顺序表与链表的总结

一、双向链表

前面我们讲过单链表,我们知道他是单向不带头,不循环链表结构,而双向链表就不一样了,双向链表是:带头的双向循环链表。

前面我们将链表的分类,但没有具体展现每一种链表到底是什么样的;是因为怕大家混淆,当时为了方便理解就把单链表的第一个节点当作是头节点;但实际上单链表是每一头节点的。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
既然双链表是双向带头的循环链表,那么将上面这几种结构结合起来自然就得到了双链表的结构:
在这里插入图片描述

注意:这里的“带头”跟前面我们说的“头结点”是两个概念,实际前⾯的在单链表阶段称呼不严谨,但是为了同学们更好的理解就直接称为单链表的头结点。

带头链表里的头结点,实际为“哨兵位”,哨兵位结点不存储任何有效元素,只是站在这⾥“放哨 的”

二,双向链表的实现

首先要实现双链表我们就要创建一个双链表与单链表的实现一样。
在.h文件中

//需要包含的头文件
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int LTData;
//双向链表的构建
typedef struct ListNode
{LTData data;struct ListNode* next;struct ListNode* prev;
}LTNode;

构建好双链表后,我们可以发现双链表比单链表多了一个prev指针,指向它的前一个节点。这一点与单链表很不一样,仅仅多了一个prev指针就使得了链表变得循环起来。而且在单链表中是不能往前遍历的,但在双链表中就可以。

在这里插入图片描述

紧接着我们初始化节点:

//初始化新节点
LTNode* LTNodeInit();
//封装一个开辟一个结点的函数   
LTNode* LTBuyNode(LTData x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){//到这说明开辟失败perror("malloc fail!");exit(1);}//到这说明开辟成功 调节新结点的prev和head指针 指向自己 因为时双向链表newnode->prev = newnode;newnode->next = newnode;newnode->data = x;//调整完后返回新结点的地址return newnode;
}//初始化
LTNode* LTNodeInit()
{LTNode* phead = LTBuyNode(-1);//向内存申请一块空间 代表一个头结点 return phead;//返回头结点的地址
}

在这里插入图片描述
创建好双链表,初始化节点后我们就可以来实现双链表的增,删,查,改了。

一,增

1,头插

在这里插入图片描述

//头插
void LTPushFront(LTNode* phead, LTData x);
//头插
void LTPushFront(LTNode* phead, LTData x)
{assert(phead);//既然要插入结点 就要先创建一个结点LTNode* newnode = LTBuyNode(x);//head newnode head->next(d1) 处理他们三个的指向关系newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;phead->next = newnode;
}

2,尾插

在这里插入图片描述

//头结点不发生改变传一级指针
//头结点要发生改变传二级指针
//尾插
void LTPushBack(LTNode* phead,LTData x);
//尾插
void LTPushBack(LTNode* phead, LTData x)
{assert(phead);//既然要尾插那么就要有新的结点 新的结点使用LTBuyNode方法开辟 然后返回新结点的地址LTNode* newnode = LTBuyNode(x);//phead  phead->prev(尾结点) newnode//先修改newnodenewnode->prev = phead->prev;//phead->prev即d3结点 newnode指向d3newnode->next = phead;//尾与头相连//再修改链表内部的结点phead->prev->next = newnode;//相当于d3->newnode d3指向newnodephead->prev = newnode;//头与尾相连
}

3,在指定位置后插入

在这里插入图片描述

//在指定位置之后插入结点
void LTInsert(LTNode* pos, LTData x);
//在指定位置之后插入结点
void LTInsert(LTNode* pos, LTData x)
{assert(pos);LTNode* newnode = LTBuyNode(x);//pos newnode pos->nextnewnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

二,删

1,头删

在这里插入图片描述

//头删
void LTPopFront(LTNode* phead);
//头删
void LTPopFront(LTNode* phead)
{assert(phead);LTNode* del = phead->next;//phead->next 为头结点//处理 head del del->nexphead->next = del->next;del->next->prev = phead;//释放头结点free(del);del = NULL;
}

2,尾删

在这里插入图片描述

//尾删
void LTPopBack(LTNode* phead);   
//尾删
void LTPopBack(LTNode* phead)
{//先判断是否是空链表assert(!LTEmpty(phead));//如果链表为空 返回1 !1(非1) 就为0 就会断言报错LTNode* del = phead->prev;//定义del来保存尾结点//处理head  head-next->prev(del->prev)     head->next(del)//             尾结点的上一个结点                   尾结点del->prev->next = phead;phead->prev = del->prev;//释放free(del);del = NULL;
}

3,删除pos位置的节点

在这里插入图片描述

//删除pos位置的结点
void LTErase(LTNode* pos);
//删除pos位置的结点
void LTErase(LTNode* pos)
{assert(pos);//pos->prev pos pos->nextpos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

三,查

在这里插入图片描述

//查找
LTNode* LTFind(LTNode* phead, LTData x);
//查找
LTNode* LTFind(LTNode* phead, LTData x)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}//走到这里已经循环完了链表都没找到 说明找不到了返回NULLreturn NULL;
}

四,链表的销毁

与单链表一样,双链表也是我们人为向操作系统申请的空间,为了避免空间浪费再我们不使用链表的时候就将他销毁,还给操作系统。
在这里插入图片描述

//链表的销毁
void LTdesTroy(LTNode*phead);
void LTdesTroy(LTNode*phead)
{LTNode*pcur=phead->next;while(pcur!=NULL){LTNode*next=pcur->next;free(pcur);pcur=next;}//跳出循环只剩下哨兵位 释放哨兵位free(phead);phead=NULL;
}

五,测试代码

以上就是双链表的实现,实现完后我们可以用一些测试代码来测试一下,

//链表的打印
//链表的打印
void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d -> ", pcur->data);pcur = pcur->next;}printf("\n");
}
void test1()
{LTNode* plist= LTNodeInit();//ʼ//β/*LTPushBack(plist,1);LTPushBack(plist,2);LTPushBack(plist,3);LTPushBack(plist,4);*/LTPushFront(plist, 1);LTPushFront(plist, 2);LTPrint(plist);
}int main()
{test1();return 0;
}

六,顺序表与链表的总结

以上就是所有链表和顺序表的内容了,我们最后再来比较一下二者的区别:
在这里插入图片描述
以上就是本章的全部内容啦!
最后感谢能够看到这里的读者,如果我的文章能够帮到你那我甚是荣幸,文章有任何问题都欢迎指出!制作不易还望给一个免费的三连,你们的支持就是我最大的动力!
在这里插入图片描述

相关文章:

【数据结构】顺序表和链表详解(下)

前言&#xff1a;上期我们从顺序表开始讲到了单链表的概念&#xff0c;分类&#xff0c;和实现&#xff0c;而这期我们来将相较于单链表没那么常用的双向链表。 文章目录 一、双向链表二&#xff0c;双向链表的实现一&#xff0c;增1&#xff0c;头插2&#xff0c;尾插3&#x…...

【系统架构设计师】绪论-系统架构概述

目录 绪论 系统架构概述 单选题 绪论 系统架构概述 单选题 1、软件方法学是以软件开发方法为研究对象的学科。其中&#xff0c;&#xff08;&#xff09;是先对最高居次中的问题进行定义、设计、编程和测试&#xff0c;而将其中未解决的问题作为一个子任务放到下一层次中去…...

SQL-事务(2025.6.6-2025.6.7学习篇)

1、简介 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 默认MySQL的事务是自动提交的&#xff0c;也就是说&#xff0…...

OpenCV 图像通道的分离与合并

一、知识点 1、一张彩色图像可以由R、G、B三个通道的灰度图合并而成。 2、void split(InputArray m, OutputArrayOfArrays mv); (1)、将多通道阵列划分为几个单通道阵列。 (2)、参数说明: m: 要分离的多通道阵列。 mv: 输出的vector容器&#xff0c;每个元素都…...

Virtex II 系列FPGA的配置原理

对FPGA 芯片的配置&#xff0c;本质上是将根据设计生成的包含配置命令和配置数据的比特流文件写入到配置存储器中。 1 配置模式 Virtex II 系列FPGA 一共有五种配置模式&#xff0c;配置模式的选择是根据管脚M[2:0]来决定。 &#xff08;1&#xff09;串行配置模式 串行配置模…...

蓝桥杯 国赛2024python(b组)题目(1-3)

第一题 试卷答题页 - 蓝桥云课 问题描述 在今年蓝桥杯的决赛中&#xff0c;一共有 1010 道题目&#xff0c;每道题目的分数依次为 55 分&#xff0c;55 分&#xff0c;1010 分&#xff0c;1010 分&#xff0c;1515 分&#xff0c;1515 分&#xff0c;2020 分&#xff0c;2020 分…...

低代码平台前端页面表格字段绑定与后端数据传输交互主要有哪些方式?华为云Astro在这方面有哪些方式?

目录 🔧 一、低代码平台中常见的数据绑定与交互方式 1. 接口绑定(API 调用) 2. 数据源绑定(DataSource) 3. 变量中转(临时变量 / 页面状态) 4. 数据模型绑定(模型驱动) 🌐 二、华为云 Astro 轻应用的实现方式 ✅ 1. 数据源绑定(API服务+API网关) ✅ 2. 变…...

stm32——UART和USART

串口通信协议UART和USART 1. UART与USART协议详解 特性UART (Universal Asynchronous Receiver/Transmitter)USART (Universal Synchronous Asynchronous Receiver/Transmitter)全称通用异步收发器通用同步/异步收发器同步/异步异步&#xff1a;不共享时钟&#xff0c;数据通过…...

算法题(165):汉诺塔问题

审题&#xff1a; 本题需要我们找到最优的汉诺塔搬法然后将移动路径输出 思路&#xff1a; 方法一&#xff1a;递归 我们先分析题目 n为2的情况&#xff0c;我们先将第一个盘子移动到三号柱子上&#xff0c;然后再将二号盘子移动到二号柱子上 n为3的情况&#xff0c;我们先将前…...

玄机——某次行业攻防应急响应(带镜像)

今天给大家带来一次攻防实战演练复现的过程。 文章目录 简介靶机简介1.根据流量包分析首个进行扫描攻击的IP是2.根据流量包分析第二个扫描攻击的IP和漏扫工具&#xff0c;以flag{x.x.x.x&工具名}3.提交频繁爆破密钥的IP及爆破次数&#xff0c;以flag{ip&次数}提交4. 提…...

低代码逻辑引擎配置化实战:三步穿透审批记录查询

在堆积如山的报销单中埋头寻找某笔特殊费用的审批轨迹在跨部门协作时被追问"这个合同到底卡在哪个环节" 在快节奏的办公自动化场景中&#xff0c;这些场景是很常见的&#xff0c;传统OA系统中分散的审批记录查询方式往往太繁琐。 为破解这一痛点&#xff0c;在JVS低…...

深入理解React Hooks的原理与实践

深入理解React Hooks的原理与实践 引言 React Hooks 自 2018 年 React 16.8 发布以来&#xff0c;彻底改变了前端开发者的编码方式。它通过函数式组件提供了状态管理和生命周期等功能&#xff0c;取代了传统的类组件&#xff0c;使得代码更加简洁、复用性更强。然而&#xff…...

WEB3技术重要吗,还是可有可无?

我从几个角度给你一个全面、理性、技术导向的回答&#xff1a; ✅ 一、Web3 技术的重要性&#xff1a;“有意义&#xff0c;但不是万能” Web3 技术并不是可有可无的噱头&#xff0c;而是一种在特定场景下提供独特价值的技术体系。 它重要的原因包括&#xff1a; 1. 重构数字…...

Python 隐藏法宝:双下划线 _ _Dunder_ _

你可能不知道&#xff0c;Python里那些用双下划线包裹的"魔法方法"(Dunder方法)&#xff0c;其实是提升代码质量的绝佳工具。但有趣的是&#xff0c;很多经验丰富的开发者对这些方法也只是一知半解。 先说句公道话&#xff1a; 这其实情有可原。因为在多数情况下&am…...

《视觉SLAM十四讲》自用笔记 第三讲:三维空间刚体运动

第三讲 三维空间刚体运动 3.0 目标 1.理解三维空间的刚体运动描述方式&#xff1a;旋转矩阵、变换矩阵、四元数和欧拉角。 2.掌握 Eigen 库的矩阵、几何模块使用方法。 3.1 旋转矩阵 3.1.1 点和向量&#xff0c;坐标系 三维空间中&#xff0c;刚体的运动可以用两个概念来…...

【Zephyr 系列 15】构建企业级 BLE 模块通用框架:驱动 + 事件 + 状态机 + 低功耗全栈设计

🧠关键词:Zephyr、BLE 模块、架构设计、驱动封装、事件机制、状态机、低功耗、可维护框架 📌面向读者:希望将 BLE 项目从“Demo 工程”升级为“企业可复用框架”的研发人员与技术负责人 📊预计字数:5500+ 字 🧭 前言:从 Demo 到产品化,架构该如何升级? 多数 BLE…...

Docker构建Vite项目内存溢出:从Heap Limit报错到完美解决的剖析

问题现象:诡异的"消失的index.html" 最近在CI/CD流水线中遇到诡异现象:使用Docker构建Vite项目时,dist目录中缺少关键的index.html文件,但本地构建完全正常。报错截图显示关键信息: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out…...

Linux运维新人自用笔记(乌班图apt命令和dpkg命令、两系统指令区别,rpm解决路径依赖、免安装配置java环境)

内容全为个人理解和自查资料梳理&#xff0c;欢迎各位大神指点&#xff01; 每天学习较为零散。 day17 一、Ubuntu apt命令和dpkg命令 二进制命令配置文件数据文件&#xff0c;打包好的单个文件 Windows &#xff1a;.exe macos&#xff1a;.dmg 后缀适用系统安装方式.d…...

vm+ubuntu24.04扩展磁盘

vmubuntu24.04扩展磁盘 $ lsblk $ sudo fdisk -l 1.修复 GPT 表警告 $ sudo parted /dev/sda print当询问是否修复时&#xff0c;输入 Fix2.扩展物理分区 /dev/sda3 $ sudo growpart /dev/sda 33.刷新物理卷 (PV) $ sudo pvresize /dev/sda3检查可用的扩展空间. $ sudo vgd…...

Python爬虫-爬取各省份各年份高考分数线数据,进行数据分析

前言 本文是该专栏的第60篇,后面会持续分享python爬虫干货知识,记得关注。 本文,笔者将基于Python爬虫,爬取各省份历年以来的“各年份高考分数线”进行数据分析。 废话不多说,具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看…...

Android端口转发

如上图所示&#xff0c;有一个Android设备&#xff0c;Android设备里面有主板&#xff0c;主板上有网络接口和Wi-Fi&#xff0c;网络接口通过网线连接了一个网络摄像头&#xff0c;这就跟电脑一样&#xff0c;电脑即可以通过网线接入一个网络&#xff0c;也可以同时用Wi-Fi接入…...

C语言 | C代码编写中的易错点总结

C语言易错点 **1. 指针与内存管理****2. 数组与字符串****3. 未初始化变量****4. 类型转换与溢出****5. 运算符优先级****6. 函数与参数传递****7. 宏定义陷阱****8. 结构体与内存对齐****9. 输入/输出函数****10. 其他常见问题****最佳实践**在C语言编程中,由于其底层特性和灵…...

PHP环境极速搭建

一、为什么选择phpStudy VS Code&#xff1f; 作为一名初次接触PHP的开发者&#xff0c;我深知环境配置往往是学习路上的第一道门槛。传统PHP环境搭建需要手动配置Apache/Nginx、PHP解释器、MySQL等多重组件&#xff0c;光是处理版本兼容性和依赖问题就可能耗费半天时间——这…...

建造者模式深度解析与实战应用

作者简介 我是摘星&#xff0c;一名全栈开发者&#xff0c;专注 Java后端开发、AI工程化 与 云计算架构 领域&#xff0c;擅长Python技术栈。热衷于探索前沿技术&#xff0c;包括大模型应用、云原生解决方案及自动化工具开发。日常深耕技术实践&#xff0c;乐于分享实战经验与…...

代码中文抽取工具并替换工具(以ts为例)

文章目录 基本思路目录结构配置文件AST解析替换代码中文生成Excel启动脚本 基本思路 通过对应语言的AST解析出中文相关信息&#xff08;文件、所在行列等&#xff09;存到临时文件通过相关信息&#xff0c;逐个文件位置替换掉中文基于临时文件&#xff0c;通过py脚本生成Excel…...

pgsql batch insert optimization (reWriteBatchedInserts )

reWriteBatchedInserts 是 PostgreSQL JDBC 驱动 提供的一个优化选项&#xff0c;它可以 重写批量插入语句&#xff0c;从而提高插入性能。 作用 当 reWriteBatchedInsertstrue 时&#xff0c;PostgreSQL JDBC 驱动会将 多个单独的 INSERT 语句 转换为 一个多行 INSERT 语句&a…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(上)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

华为云Flexus+DeepSeek征文 | 基于DeepSeek-V3构建企业知识库问答机器人实战

作者简介 我是摘星&#xff0c;一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型&#xff0c;将实际使用经验分享给大家&#xff0c;希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 作者简介 1. 引言 2. 技术选型与架构设计 2.1 技…...

【Docker 01】Docker 简介

&#x1f308; 一、虚拟化、容器化 ⭐ 1. 什么是虚拟化、容器化 物理机&#xff1a;真实存在的服务器 / 计算机&#xff0c;对于虚拟机来说&#xff0c;物理机为虚拟机提供了硬件环境。虚拟化&#xff1a;通过虚拟化技术将一台计算机虚拟为 1 ~ n 台逻辑计算机。在一台计算机…...

信息最大化(Information Maximization)

信息最大化在目标域无标签的域自适应任务中&#xff0c;它迫使模型在没有真实标签的情况下&#xff0c;对未标记数据产生高置信度且类别均衡的预测。此外&#xff0c;这些预测也可以作为伪标签用于自训练。 例如&#xff0c;在目标域没有标签时&#xff0c;信息最大化损失可以…...