双向链表<数据结构 C版>
目录
关于链表的分类
双向链表结构体
初始化
尾插
头插
打印
判断是否为空
尾删
头删
查找
指定位置之后的插入
指定位置的删除
销毁
关于链表的分类
根据链表的三大特性,单向or双向、带头or不带头、循环or不循环,可将链表分为2*2*2,8种链表,前面我们已经实现了单链表,即:不带头单向非循环链表,它的结构简单,不常用于单独存储数据,而是作为其他数据结构的子结构。
实际运用中,只有单链表(不带头单向非循环链表)和双向链表(带头双向循环链表)运用最多,带头双向循环链表,结构最复杂,常常运用于单独存储数据,使用的链表结构也几乎都是双向带头链表。
附上一张bit课件的图:

双向链表结构体
放一张bi课件的图片很形象:

//重定义一下类型,方便统一修改
typedef int LNDataType;typedef struct ListNode {LNDataType data;//数据struct ListNode* prev;//前一个结点struct ListNode* next;//后一个结点
}LN;
初始化
双向链表的初始化,应创建一个哨兵结点(也称头结点),它存放的数据是无效数据(假定-1),
所以我们先实现一个创建单节点的函数:
//创建新节点
LN* LNBuyNode(LNDataType x) {LN* node = (LN*)malloc(sizeof(LN));//开辟空间if (!node) {//判断为空perror("malloc fail!");exit(1);}node->data = x;//传入数据node->next = node->prev = node;//双向循环链表单节点也应满足循环,不能初始化为NULL;return node;
}
接着我们就可方便地调用,创建一个哨兵结点:
//初始化
void LNInit(LN** pphead) {assert(pphead);*pphead=LNBuynode(-1);
}
尾插
//尾插
void LNPushBack(LN* phead, LNDataType x) {assert(phead);LN* node = LNBuyNode(x);//创建新结点node->next = phead;//先对新申请的结点参数进行操作,防止对原链表造成改变node->prev = phead->prev;phead->prev->next = node;//更改尾结点的next参数的指向phead->prev = node;//更改头结点prev结点的指向
}
运行测试一下:

头插
注意头插的操作是在哨兵位后插入,双向链表为空的情况也是只剩下哨兵位,因为哨兵位并没有存储有效数据。
//头插
void LNPushFront(LN* phead, LNDataType x) {assert(phead);LN* node = LNBuyNode(x);//创建新结点node->next = phead->next;//先对新申请的结点参数进行操作,防止对原链表造成改变node->prev = phead;phead->next->prev = node;//更改头结点的下一个结点的prev指向phead->next = node;//更改头结点的next指向
}
运行测试一下:

打印
//打印
void LNPrint(LN* phead) {assert(phead);LN* pcur = phead->next;//因为头结点内存储的是无效数据,所以我们让它指向下一个结点while (pcur!=phead) {//与头结点相遇说明我们已经遍历完整个链表了printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}
判断是否为空
双向链表为空的情况是只有一个哨兵结点而不是NULL
//判断是否为空
bool LNEmpty(LN* phead) {assert(phead);return phead->next == phead;
}
尾删
//尾删
void LNPopBack(LN* phead) {assert(phead);assert(!LNEmpty(phead));//删除操作至少有一个有效数据//LNEmptys是空返回true,取反保证不为空LN* del = phead->prev;//保存要删除的结点phead->prev = del->prev;//对要受影响的结点的参数进行更改phead->prev->next = phead;free(del);//释放掉该地址del = NULL;
}
运行测试一下:

头删
//头删
void LNPopFront(LN* phead) {assert(phead);assert(!LNEmpty(phead));LN* del = phead->next;//保存要删除的结点phead->next = del->next;//对要受影响的结点的参数进行更改phead->next->prev = phead;free(del);//释放掉该地址del = NULL;
}
运行测试一下:

查找
因为后面涉及到任意位置的操作,所以这里要写一个查找方法:
//查找
LN* LNFind(LN* phead, LNDataType x) {assert(phead);assert(!LNEmpty(phead));LN* pcur = phead->next;while (pcur!=phead) {//判断条件为!=phead,遇到哨兵位说明已经遍历完if (pcur->data == x) {return pcur;}pcur = pcur->next;}return NULL;
}
运行测试一下:

指定位置之后的插入
//指定位置之后的插入
void LNInsert(LN* pos, LNDataType x) {assert(pos);LN* node = LNBuyNode(x);node->next = pos->next;//先对要受影响的结点的参数进行更改node->prev = pos;pos->next->prev = node;//更改pos结点的后一个结点的prev参数pos->next = node;//更改pos结点的next参数
}
运行测试一下:

指定位置的删除
//任意位置的删除
void LNErase(LN* pos) {assert(pos);pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}
运行测试一下:

销毁
//销毁
void LNDestory(LN** phead) {assert(phead && *phead);LN* pcur = (*phead)->next;while (pcur != *phead) {LN* next = pcur->next;free(pcur);pcur = next;}free(*phead);*phead =pcur= NULL;
}
相关文章:
双向链表<数据结构 C版>
目录 关于链表的分类 双向链表结构体 初始化 尾插 头插 打印 判断是否为空 尾删 头删 查找 指定位置之后的插入 指定位置的删除 销毁 关于链表的分类 根据链表的三大特性,单向or双向、带头or不带头、循环or不循环,可将链表分为2*2*2…...
react18+
主要是围绕函数式组件讲,18主要用就是函数式组件,学习前先熟悉下原生js的基本使用,主要是事件 1、UI操作 1.1、书写jsx标签语言 基本写法和原生如同一则,只是放在一个方法里面返回而已,我们称这样的写法为函数式组件…...
rk3568 OpenHarmony4.1 Launcher定制开发—桌面壁纸替换
Launcher 作为系统人机交互的首要入口,提供应用图标的显示、点击启动、卸载应用,并提供桌面布局设置以及最近任务管理等功能。本文将介绍如何使用Deveco Studio进行单独launcher定制开发、然后编译并下载到开发板,以通过Launcher修改桌面背景…...
MySQL:送分or送命 varchar(30) 与 int(10)
摘要: VARCHAR(30) 和 INT(10) 在MySQL中代表两种不同类型的字段,它们之间的主要区别在于它们存储的数据类型、存储方式以及显示宽度的含义。 正文: INT(10) 在MySQL中,当你看到INT(10)这样的数据类型定义时,可能会…...
【odoo17】后端py方法触发右上角提示组件
概要 在前面文章中,有介绍过前端触发的通知服务。 【odoo】右上角的提示(通知服务) 此文章则介绍后端触发方法。 内容 直接上代码:但是前提一定是按钮触发!!!!! def bu…...
1775D - Friendly Spiders
题目链接:Friendly Spiders 首先我们可以考虑暴力做法,那就是每两个蜘蛛判断一下gcd,如果不等于1,那就连条边,这样的话时间复杂度是O(n^2),显然超时,因此我们可以采用类似…...
【python】OpenCV—Point Polygon Test
文章目录 1、完整代码2、涉及到的库cv2.pointPolygonTestcv2.minMaxLoc 1、完整代码 from __future__ import print_function from __future__ import division import cv2 as cv import numpy as np # Create an image r 100 src np.zeros((4*r, 4*r), dtypenp.uint8) # 创…...
6 Go语言的常量、枚举、作用域
本专栏将从基础开始,循序渐进,由浅入深讲解Go语言,希望大家都能够从中有所收获,也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方,请指正!大家一起学习,…...
第十一章 数据结构
第十一章 数据结构 11.1 数组 数组是元素的顺序集合,通常这些元素具有相同的数据类型 索引表示元素在数组中的顺序号,顺序号从数组开始处计数 数组元素通过索引被独立给出了地址,数组整体上有一个名称,但每个元素利用数组的的…...
LeetCode704 二分查找
前言 题目: 704.二分查找 文档: 代码随想录——二分查找 编程语言: C 解题状态: 解答错误,变量定义位置错误。 思路 有序数组的查找,最直接的思路应该就是二分查找。但是在查找的过程中要考虑到区间的边界…...
[言简意赅] Matlab生成FPGA端rom初始化文件.coe
🎎Matlab生成FPGA端rom初始化文件.coe 本文主打言简意赅。 函数源码 function gencoeInitialROM(width, depth, signal, filepath)% gencoeInitialROM - 生成 Xilinx ROM 初始化格式的 COE 文件%% 输入参数:% width - ROM 数据位宽% depth - ROM 数据深度% s…...
【QAC】分布式部署下其他机器如何连接RLM
1、 文档目标 解决分布式部署下其他机器如何连接RLMLicense管理器。 2、 问题场景 分布式部署下QAC要在其他机器上单独运行扫描,必须先连接RLMLicense管理器,如何连接? 3、软硬件环境 1、软件版本:HelixQAC23.04 2、机器环境…...
从等保测评看行业安全趋势:洞察与预测
在当今数字化时代,网络安全已成为各行各业的头等大事。等保测评(等级保护测评),作为国家对信息系统安全的重要管理手段,不仅关乎企业的合规性,更是行业安全水平的重要衡量标准。本文将从等保测评的视角出发…...
HTTP模块(二)
HTTP 设置 HTTP 响应报文 HTTP报文常见属性: const http require(http);const server http.createServer((request, response) > {// 设置请求状态码 2xx 4xx 5xxresponse.statusCode 200;// 设置请求描述 了解即可response.statusMessage hello// 指定响…...
引入缓存带来的问题以及解决方案
目录 前言 问题与解决方案 缓存击穿 缓存穿透 缓存雪崩 缓存一致性 前言 在提升接口性能的方案中,毫无疑问,使用缓存是最有效果的,但同时也会带来新的问题。 缓存击穿缓存穿透缓存雪崩缓存一致性 以上问题都是引入缓存需要考虑的&am…...
力扣39题:组合总和的 Java 实现
引言 力扣(LeetCode)是一个在线编程平台,提供了大量的编程题目供开发者练习。第39题“组合总和”是一个经典的回溯算法问题,要求找出所有可能的组合,使得组合中的数字之和等于给定的目标值。本文将介绍如何使用 Java …...
使用el-table实现自动滚动
文章目录 概要技术实现完整代码 概要 在前端开发大屏的时候,我们会用到表格数据展示,有时候为了使用户体验更加好,会增加表格自动滚动。下边我将以示例代码,用element UI的el-table来讲一下。 技术实现 1 .增加dom监听…...
Angular由一个bug说起之八:实践中遇到的一个数据颗粒度的问题
互联网产品离不开数据处理,数据处理有一些基本的原则包括:准确性、完整性、一致性、保密性、及时性。 准确性:是数据处理的首要目标,确保数据的真实性和可靠性。准确的数据是进行分析和决策的基础,因此…...
day13(DNS域名解析)
今天内容: 1、逆向解析 2、多域名 3、时间服务器 4、主从配置 1.设置逆向解析 (1)永久配置我们自己的DNS服务器 (2)关闭NetworkManager服务 NetworkManager 的自动管理功能可能会干扰定制化的网络配置。 在需要切换…...
uboot的mmc partconf命令
文章目录 命令格式参数解释具体命令解释总结 mmc partconf 是一个用于配置 MMC (MultiMediaCard) 分区的 U-Boot 命令。具体来说,这个命令允许你设置或读取 MMC 卡的分区配置参数。让我们详细解释一下 mmc partconf 0 0 1 0 命令的含义。 命令格式 mmc partconf &…...
深入OpenBMC散热控制:从IPMI命令到D-Bus,揭秘手动与自动模式切换
深入OpenBMC散热控制:从IPMI命令到D-Bus,揭秘手动与自动模式切换 在数据中心和服务器运维领域,散热控制一直是系统稳定性的关键因素。OpenBMC作为开源基板管理控制器,其散热管理机制直接影响到服务器的可靠性和能效比。本文将带您…...
AI 大模型落地系列|Eino 组件核心篇:ChatTemplate 为什么不是字符串拼接
声明:本文数据源于官方文档与官方实现,重点参考 ChatTemplate 使用说明。 为什么很多人学 Eino 后,写 Prompt 时还是把 ChatTemplate 用成了字符串拼接?1. ChatTemplate 是什么,不是什么2. 接口虽短,但起的…...
5分钟解锁WeMod专业版:开源工具让你的游戏修改体验全面升级
5分钟解锁WeMod专业版:开源工具让你的游戏修改体验全面升级 【免费下载链接】Wemod-Patcher WeMod patcher allows you to get some WeMod Pro features absolutely free 项目地址: https://gitcode.com/gh_mirrors/we/Wemod-Patcher 还在为WeMod专业版的订阅…...
OpenClaw终端整合:QwQ-32B命令行操作增强方案
OpenClaw终端整合:QwQ-32B命令行操作增强方案 1. 为什么需要终端智能助手 作为开发者,我们每天要处理大量命令行操作。从简单的目录跳转、文件操作,到复杂的管道命令组合,再到调试报错信息,这些重复性工作消耗了大量…...
AI性能测试:TPS之外还要关注什么?
在AI驱动的时代,性能测试已成为软件测试从业者的核心技能。传统软件测试中,TPS(Transactions Per Second,每秒事务处理量)常被视为黄金指标,用于衡量系统的吞吐能力。然而,AI系统因其独特的计算…...
【超全】基于Springboot多维分类的知识管理系统【包括源码+文档+调试】
💕💕发布人: 码上青云 💕💕各类成品Java毕设 。javaweb,ssm,springboot等项目,欢迎咨询。 💕💕程序开发、技术解答、代码讲解、文档, ἱ…...
C语言回调函数在TCP客户端中的实现与应用
C语言回调函数在TCP客户端中的实现与应用1. 回调函数基础概念回调函数是一种通过函数指针实现的编程机制,允许将一个函数作为参数传递给另一个函数。在C语言中,回调函数的实现完全依赖于函数指针,这与C、Python等现代语言中可能使用仿函数或匿…...
37 Python 时序和文本:词袋模型 BoW 和 TF-IDF 到底怎么理解?
Python 文本分析入门:词袋模型 BoW 和 TF-IDF 到底怎么理解? 上一篇主要解决了两个基础问题: 为什么中文文本通常要先分词?为什么分词之后还要做停用词过滤? 但文本清洗完成之后,新的问题很快就会出现&…...
基于微信小程序实现马拉松报名系统【附项目源码+论文说明】
基于java和微信小程序实现马拉松报名系统演示【内附项目源码LW说明】摘要 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了马拉松报名系统微信小程序的开发全过程。通过分析马拉松报名系统微信小程序管理的不足&…...
【SpringBoot】scanBasePackages实战:从默认扫描到精准控制的进阶指南
1. 为什么需要自定义组件扫描路径 第一次用SpringBoot开发项目时,我发现只要把启动类放在顶层包下,所有子包的组件都能自动注册。这种"开箱即用"的特性确实方便,但后来接手一个老项目时遇到了问题:启动耗时长达2分钟&am…...
