链接未来:深入理解链表数据结构(二.c语言实现带头双向循环链表)
上篇文章简述讲解了链表的基本概念并且实现了无头单向不循环链表:链接未来:深入理解链表数据结构(一.c语言实现无头单向非循环链表)-CSDN博客
那今天接着给大家带来带头双向循环链表的实现:

文章目录
- 一.项目文件规划
- 二.基本结构及功能一览(DoubleList.h)
- 结构体定义
- 接口功能一览
- 三.各功能接口具体实现
- 1.创建节点
- 2.初始化
- 3.打印
- 4.尾插
- 5.尾删
- 6.头插
- 7.头删
- 8.查找
- 9.插入pos前
- 10.删除pos位置
- 11.销毁
- 四.利用插入和删除改变“两插两删”(快速写出链表)
一.项目文件规划

- 头文件DoubleList.h:用来基础准备(常量定义,typedef),链表表的基本框架,函数的声明
- 源文件DoubleList.h:用来各种功能函数的具体实现
- 源文件test.c:用来测试功能是否有问题,进行基本功能的使用
二.基本结构及功能一览(DoubleList.h)
结构体定义
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;//下一个节点struct ListNode* prev;//上一个节点LTDataType val;//数据
}LTNode;
接口功能一览
LTNode* LTInit();//初始化
void LTPrint(LTNode* phead);//打印数据void LTPushBack(LTNode* phead, LTDataType x);//尾插
void LTPopBack(LTNode* phead);//尾删
void LTPushFront(LTNode* phead, LTDataType x);//头插
void LTPopFront(LTNode* phead);//头删LTNode* LTFind(LTNode* phead, LTDataType x);//查找
void LTInsert(LTNode* pos, LTDataType x);//在pos前插入
void LTErase(LTNode* pos);//删除posvoid LTDestroy(LTNode* phead);//销毁
三.各功能接口具体实现
1.创建节点
因为后面尾插,头插,插入,初始化都要用到创建新节点,所以抽出来作为一个函数
LTNode* CreateLTNode(LTDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));//动态开辟if (newnode == NULL){perror("malloc");return -1;}newnode->val = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}
2.初始化
1.第一种:返回动态开辟的地址(不会销毁)
LTNode* LTInit()
{LTNode* a =CreateLTNode(-1);a->next = a;//一开始一个节点时,下一个和上一个都指向自己a->prev = a;//return a;
}
2.第二种:传入二级指针(要直接改变头节点的值)
void LTInit(LTNode** pphead)
{*pphead = CreateLTNode(-1);(*pphead)->next = *pphead;(*pphead)->prev = *pphead;
}
这两种皆可
3.打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;//头结点数据无效,不需要打印while (cur != phead){printf("%d ", cur->val);cur = cur->next;}printf("\n");
}
4.尾插

void LTPushBack(LTNode* phead, LTDataType x)//无有效节点也适用
{assert(phead);LTNode* newnode = CreateLTNode(x);LTNode* tail = phead->prev;// phead tail newnode 位置展示newnode->next = phead;phead->prev = newnode;newnode->prev = tail;tail->next = newnode;
}
5.尾删

void LTPopBack(LTNode* phead)//只有一个有效节点也适用
{assert(phead);LTNode* tail = phead->prev;LTNode* pretail = tail->prev;// phead pretail tail 位置展示free(tail);tail = NULL;phead->prev = pretail;pretail->next = phead;
}
6.头插

void LTPushFront(LTNode* phead, LTDataType x)//无有效节点也适用
{assert(phead);LTNode* newnode = CreateLTNode(x);//phead newnode firest tail 位置展示newnode->next = phead->next;phead->next->prev = newnode;newnode->prev = phead;phead->next = newnode;
}
7.头删

void LTPopFront(LTNode* phead)
{assert(phead);assert(phead->next != phead);//只有哨兵位时不能删LTNode* first = phead->next;LTNode* second = first->next;//phead first second tail 位置展示free(first);first = NULL;phead->next = second;second->prev = phead;
}
8.查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);assert(phead->next != phead);//只有哨兵位时没必要查LTNode* cur = phead->next;while (cur != phead){if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}
9.插入pos前
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = CreateLTNode(x);LTNode* pre = pos->prev;//pre newnode pos tail 位置展示pre->next = newnode;newnode->prev = pre;newnode->next = pos;pos->prev = newnode;
}
- 将前一个节点
pre的next指针指向新节点newnode- 将新节点
newnode的prev指针指向前一个节点pre- 将新节点
newnode的next指针指向指定节点pos- 将指定节点
pos的prev指针指向新节点newnode
10.删除pos位置

void LTErase(LTNode* pos)
{assert(pos);LTNode* pre = pos->prev;LTNode* next = pos->next;//pre pos next tail 位置展示pre->next = next;next->prev = pre;free(pos);pos = NULL;
}
11.销毁
因为每个节点时malloc动态开辟出来的,要把每个节点都依次销毁
void LTDestroy(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur->next != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;
}
四.利用插入和删除改变“两插两删”(快速写出链表)
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTInsert(phead, x);//尾插就是在phead前插入
}void LTPopBack(LTNode* phead)
{assert(phead);assert(phead->next != phead);LTErase(phead->prev);
}void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTInsert(phead->next, x);//头插就是插入到phead的下一个
}void LTPopFront(LTNode* phead)
{assert(phead);assert(phead->next != phead);LTErase(phead->next);
}
那这次就先到这里啦!两种常见的链表都已经实现完毕,接下来大概率是栈和队列了,感谢大家支持
相关文章:
链接未来:深入理解链表数据结构(二.c语言实现带头双向循环链表)
上篇文章简述讲解了链表的基本概念并且实现了无头单向不循环链表:链接未来:深入理解链表数据结构(一.c语言实现无头单向非循环链表)-CSDN博客 那今天接着给大家带来带头双向循环链表的实现: 文章目录 一.项目文件规划…...
论文笔记 | Nature 2023 FunSearch:利用大语言模型在数学科学领域探索新的发现
文章目录 一、前言二、主要内容三、总结🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 科学中有许多难以解决的问题,这些问题难以获得确切解答,但却相对容易进行验证。在数学和计算机科学领域,这类问题被称为 NP 完全优化问题(NP-complete optimization pr…...
JavaScript 对象和 JSON 字符串的区别
JavaScript 对象和 JSON 字符串是两种不同的数据表示形式,它们有以下区别: 语法格式:JavaScript 对象是 JavaScript 语言中的一种数据类型,使用花括号 {} 包裹,属性和值之间使用冒号 : 分隔,并且使用逗号 …...
基于 Flink SQL 和 Paimon 构建流式湖仓新方案
目录 1. 数据分析架构演进 2. Apache Paimon 3. Flink + Paimon 流式湖仓 Consumer 机制 Changelog 生成编辑...
MFC静态链接+libtiff静态链接提示LNK2005和LNK4098
编译报错 1>msvcrt.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_infoAAEABV0Z) 已经在 libcmtd.lib(typinfo.obj) 中定义 1>msvcrt.lib(ti_inst.obj) : error LNK2005: "pr…...
桶装水送水小程序:提升服务质量的利器
随着移动互联网的发展,越来越多的消费者通过手机在线购物和订购商品。如果你是一名桶装水供应商,想要拓展线上业务,那么开发一个桶装水微信小程序将是一个明智的选择。本文将指导你从零开始开发一个桶装水微信小程序,让你轻松完成…...
深度学习在训练什么,什么是模型
深度学习是机器学习的一个分支,它主要通过使用称为神经网络的复杂结构来学习数据的表征。在深度学习中,"训练"和"模型"是两个核心概念。 训练 在深度学习中,"训练"是指用数据来训练一个神经网络。这个过程涉…...
Andorid 使用bp或者mk编译C文件生成so
在Aosp源码里编译C文件生成so 使用mk编译 文件夹列表 CMkDemo/Android.mk CMkDemo/cpp/SerialPort.c CMkDemo/cpp/SerialPort.hAndroid.mk 内容如下 LOCAL_PATH: $(call my-dir) include $(CLEAR_VARS)LOCAL_MODULE_TAGS : optional# All of the source files that we will…...
只更新软件,座椅为何能获得加热功能?——一文读懂OTA
2020年,特斯拉发布过一次OTA更新,车主可以通过这次系统更新获得座椅加热功能。当时,这则新闻震惊了车圈和所有车主,彼时的大家还没有把汽车当作可以“升级”的智能设备。 如今3年过去了,车主对各家车企的OTA升级早已见…...
EfficientDet:Scalable and Efficient Object Detection中文版 (BiFPN)
EfficientDet: Scalable and Efficient Object Detection EfficientDet:可扩展和高效的目标检测 摘要 模型效率在计算机视觉中变得越来越重要。本文系统地研究了用于目标检测的神经网络架构设计选择,并提出了几个关键的优化方法来提高效率。首先&…...
视频监控技术经历了哪些发展阶段?视频监控技术未来趋势展望
随着城市经济的发展和进步,视频监控也已经应用在人们衣食住行的方方面面,成为社会主体的一个重要组成部分。随着视频监控的重要性越来越凸显,大家对视频监控技术的发展也非常关注。今天我们来简单阐述一下,视频监控技术经历的几个…...
德人合科技 | 设计公司文件加密系统——天锐绿盾自动智能透明加密防泄密系统
设计公司文件加密系统——天锐绿盾自动智能透明加密防泄密系统 PC端访问地址: www.drhchina.com 一、背景介绍 设计公司通常涉及到大量的创意作品、设计方案、客户资料等重要文件,这些文件往往包含公司的核心价值和商业机密。因此,如何确保…...
类和对象(下篇)
再谈构造函数 构造函数体赋值 在之前的学习中我们知道,在创建一个对象时,我们的编译器就会自动调用构造函数将对象初始化,给对象中各个成员变量一个合适的初始值。 例如: class Date { public:Date(int year, int month, int d…...
华为鸿蒙(HarmonyOS):连接一切,智慧无限
华为鸿蒙是一款全场景、分布式操作系统,旨在构建一个真正统一的硬件生态系统。该操作系统于2019年8月首次发布,并被设计为可以应用于各种设备,包括智能手机、智能手表、智能电视、车载系统等多种智能设备。 推荐一套最新版的鸿蒙4.0开发教程 …...
劈窗算法反演地表温度
目录 摘要操作步骤提取热红外单波段提取NDVI同步像元分辨率与个数劈窗算法地表温度反演制图 摘要 主要使用HJ-2(环境减灾二号卫星)的IRS传感器的两个热红外波段,以及红波段与近红波段计算得到的NDVI,使用劈窗算法,得到…...
持续集成交付CICD:基于ArgoCD 的GitOps 自动化完成前端项目应用发布与回滚
目录 一、实验 1. 环境 2. K8S master节点部署Argo CD 3.基于ArgoCD 实现GitOps (同步部署文件) 4.基于ArgoCD 实现GitOps (同步HELM文件) 二、问题 1. ArgoCD 连接K8S集群状态为 Unknown 2.ArgoCD 创建application失败 …...
SSH无密登陆配置
1 SSH介绍 ssh命令用于远程登录到其他计算机,实现安全的远程管理。 基本语法: ssh 域名/IP地址 示例: (1)从hadoop100服务器上远程连接hadoop101服务器 [hadoophadoop100 ~]$ ssh hadoop101 如果出现如下内容 Ar…...
【bug日记】如何切换jdk版本,如何解决java和javac版本不一致
背景 今天在安装jenkins后,使用java运行war包的时候,提示jdk1.8版本太低,需要提高版本,所以就需要切换jdk版本 解决 在用户变量中,首先更改了JAVA_HOME的地址为17的目录,发现javac的版本改为17了&#x…...
【C语言】6-5 判断回文字符串 分数 20
6-5 判断回文字符串 分数 20 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求编写函数,判断给定的一串字符是否为“回文”。所谓“回文”是指顺读和倒读都一样的字符串。如“XYZYX”和“xyzzyx”都是回文。 函数接口定义: bool palindr…...
STL中优先队列(堆)的详解
文章目录 priority_queue的基本介绍堆(heap)堆的概念与结构 priority_queue 的介绍与使用 priority_queue的基本介绍 这个priority_queue翻译成中文就是优先级队列,但其实我们很难去一眼看出他的意思到底是什么,他的逻辑结构实际上类似于数据结构中的堆…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
GraphRAG优化新思路-开源的ROGRAG框架
目前的如微软开源的GraphRAG的工作流程都较为复杂,难以孤立地评估各个组件的贡献,传统的检索方法在处理复杂推理任务时可能不够有效,特别是在需要理解实体间关系或多跳知识的情况下。先说结论,看完后感觉这个框架性能上不会比Grap…...
raid存储技术
1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划,涵盖存储系统的布局、数据存储策略等,它明确数据如何存储、管理与访问,为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...
后端解决跨域问题的三种方案:注解配置 vs 全局配置 vs 过滤器配置(附完整代码详解)
文章目录 一、引言:跨域问题的本质与解决方案分类解决方案分类二、方案一:`WebMvcConfigurer` 全局配置(推荐)1. 核心代码(你提供的 `CorsConfig` 示例)2. 代码详解3. 优点4. 注意事项三、方案二:`CorsFilter` 过滤器配置(传统方式)1. 核心代码(你提供的 `ResourcesC…...
