带头结点的双向循环链表
目录
带头结点的双向循环链表
1.存储定义
2.结点的创建
3.结点的初始化
4.尾插结点
5.尾删结点
6.头插结点
7.头删结点
8.查找并返回结点
9.在pos结点前插入结点
10.删除pos结点
11.打印链表
12.销毁链表
13.头插结点2.0版
14.尾插结点2.0版
前言:
当我们使用单链表时,想要去找到前面的前驱结点的时候,我们发现了受到限制,因为当时的结点只能去找后面的结点。
于是,就到了这里的带头结点的双向循环链表。
如图:

首先给出 双向链表的定义:是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。
那双向循环链表就是最后一个结点的next指向头结点,头结点的前驱指向尾结点。
带头结点的双向循环链表
1.存储定义
typedef int CLDataType;typedef struct ListNode
{CLDataType val;struct ListNode* next; //存放后面结点的指针struct ListNode* pre; //存放前面结点的指针
}ListNode;
2.结点的创建
结点的创建,刚开始创建头结点我们一般会采用二级指针的方式,这里我们采用使用函数返回值的形式来避免野指针问题。
//创建链表
ListNode* CreateNode(CLDataType x)
{//这里采用返回值的形式进行创建结点ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));if (newnode == NULL) {perror("malloc");exit(-1);}newnode->val = x;newnode->pre = NULL;newnode->next = NULL;return newnode;
}
如果是刚开始创建的头节点的话:

3.结点的初始化
这个时候就能体现带头结点双向循环链表的好处了
ListNode* InitNode()
{ListNode* phead = CreateNode(-1);//让头节点的前驱和后继结点都指向自己phead->next = phead; phead->pre = phead;return phead;
}
因为修改了头结点,所以接着使用函数返回值的形式。
注意:初始化时,头结点的前驱和后继指针都指向自己。如图:

4.尾插结点
之前的单链表尾插需要遍历整个链表去找尾结点,但是,这里是带头结点的双向循环链表,只需去找头结点的前驱结点就找到了尾结点。
//尾插结点
void ListPushBack(ListNode* phead, CLDataType x)
{assert(phead);ListNode* newnode = CreateNode(x);ListNode* tail = phead->pre;tail->next = newnode; //之前的尾结点的后继指针指向新结点newnode->pre = tail; //新结点的前驱指向之前的尾结点newnode->next = phead; //新结点的后继指针指向头结点phead->pre = newnode; //头结点的前驱指向
当链表中只有一个头结点的时候,tail指向自己。

再继续尾插时,仍是这样。

5.尾删结点
一般都是先找到尾节结点,然后再去找到尾结点的前一个结点Pre。Pre指向头结点,头结点的前驱指向Pre。之后再删去尾节结。
//尾删结点
void ListPopBack(ListNode* phead)
{assert(phead);assert(phead->next != phead); //避免只有一个头结点ListNode* tail = phead->pre;ListNode* Pre = tail->pre; //用来记录尾结点的前一个结点Pre->next = phead;phead->pre = Pre;free(tail);tail = NULL;
}
注意:当只有一个头结点的情况时,说明已经没有链表结点。所以不能进行删除。进而这里采用,assert( phead->next != phead) 来避免此情况。
6.头插结点
和单链表的头插相似,用next指针记录头结点的下一个结点。先让新结点与next指针指向的结点建立连接,再与头结点建立连接。
//头插结点
void ListPushFront(ListNode* phead,CLDataType x)
{assert(phead);ListNode* newnode = CreateNode(x);ListNode* next = phead->next; //记录头结点后的第一个结点newnode->next = next;next->pre = newnode;phead->next = newnode;newnode->pre = phead;
}

7.头删结点
这里需要注意的是避免只有一个头结点的情况下,删除结点,这样使用同尾删结点一样的方法,通过断言 assert(phead->next != phead);
//头删结点
void ListPopFront(ListNode* phead)
{assert(phead);assert(phead->next != phead);phead->next = phead->next->next;phead->next->next->pre = phead;
}

8.查找并返回结点
这里采用cur指针去遍历链表,找到就返回结点,没有找到就返回空。
//查找并返回结点
ListNode* ListFind(ListNode* phead, CLDataType x)
{assert(phead);ListNode* cur = phead->next;while (cur != phead) {if (cur->val == x){return cur;}cur = cur->next;}return NULL;
}
9.在pos结点前插入结点
因为是带头结点的双向循环链表,这样就可以直接进行插入。
//在pos前面插入结点
void ListInsert(ListNode* pos, CLDataType x)
{assert(pos);ListNode* newnode = CreateNode(x);//注意顺序//先让后驱建立连接newnode->next = pos;pos->pre->next = newnode;//再前驱建立连接newnode->pre = pos->pre;pos->pre = newnode;
}


10.删除pos结点
修改pos的前驱和后继
//删除pos位置的结点
void ListErase(ListNode* pos)
{assert(pos);pos->pre->next = pos->next;pos->next->pre = pos->pre;
}

11.打印链表
//打印链表
void ListPrint(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;printf("phead<==>");while (cur != phead) {printf("%d<==>", cur->val);cur = cur->next;}printf("\n");
}
12.销毁链表
//销毁链表
void ListDestory(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;while (cur != phead){ListNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;
}
13.头插结点2.0版
这里我们借助 在pos结点前插入结点 的接口。
头插结点,那就是把pos结点变为 phead->next 的结点。这样结点的插入就模拟了头插结点,从而减少了一写代码的工作量。
//头插结点2.0
void ListushFront(ListNode* phead, CLDataType x)
{assert(phead);ListNode* newnode = CreateNode(x);ListNode* next = phead->next; //记录头结点后的第一个结点ListInsert(next,x); //这里的next相当于pos结点
}
例如 :在 1结点 前插入 结点25

14.尾插结点2.0版
根据带头结点的双向循环链表的特性,再借助前面的 在pos结点前插入结点(ListInsert) 的接口
这时我们会想到的就是 尾插结点不是在尾结点的后面进行插入的吗,而ListInsert是在pos前面进行结点的插入。 这时就采用 在头结点的前进行插入结点,从而达到尾插结点的特性。
//尾插结点
void ListPushBack(ListNode* phead, CLDataType x)
{assert(phead);ListNode* newnode = CreateNode(x);ListInsert(phead,x);
}

相关文章:
带头结点的双向循环链表
目录 带头结点的双向循环链表 1.存储定义 2.结点的创建 3.结点的初始化 4.尾插结点 5.尾删结点 6.头插结点 7.头删结点 8.查找并返回结点 9.在pos结点前插入结点 10.删除pos结点 11.打印链表 12.销毁链表 13.头插结点2.0版 14.尾插结点2.0版 前言: 当…...
2023年11月下旬大模型新动向集锦
2023年11月下旬大模型新动向集锦 2023.12.1版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 1、微软将向中国大陆开放Windows Copilot服务 据微软发布的消息,微软将在 2023 年 12 月 1 日面向中国大陆的企业和教育机构推出 We…...
有IP没有域名可以申请证书吗?
一、IP证书是什么? ip证书是用于公网ip地址的SSL证书,与我们通常所讲的SSL证书并无本质上的区别,但由于SSL证书通常颁发给域名,而组织机构需要公共ip地址的SSL证书,这类SSL证书就是我们所说的ip证书。ip证书具有安全、…...
【软件推荐】卸载360软件geek;护眼软件flux;
卸载360软件geek f.lux: software to make your life better (justgetflux.com) 卸载完扫描残留 护眼软件 hf.lux: software to make your life better (justgetflux.com)https://justgetflux.com/https://justgetflux.com/...
Module build failed: Error: ENOENT: no such file or directory
前言 这个错误通常发生在Node.js 和 vue,js项目中,当你试图访问一个不存在的文件或目录时。在大多数情况下,这是因为你的代码试图打开一个不存在的文件,或者你的构建系统(例如Webpack)需要一个配置文件,但找…...
Postgresql BatchInsert唯一键冲突及解决
Postgresql BatchInsert唯一键冲突及解决 当有唯一键冲突时,批量插入可能会报错; insert into tableA(sno,name,age,emp) values(),(),(); 会报错 insert into tableA(sno,name,age,emp) values(),(),() on conflict on contraint tableA_unique_key do …...
腾讯云AMD服务器标准型SA5实例AMD EPYC Bergamo处理器
腾讯云服务器标准型SA5实例是最新一代的标准型实例,CPU采用AMD EPYC™ Bergamo全新处理器,采用最新DDR5内存,默认网络优化,最高内网收发能力达4500万pps。腾讯云百科txybk.com分享腾讯云标准型SA5云服务器CPU、内存、网络、性能、…...
力扣 --- 加油站
题目描述: 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 给定两个…...
C++基础 -25- 动态多态
静态多态在程序编译的时候,确定将要执行的状态。 动态多态在程序运行的时候,才能确定执行的状态。 下面举例实现动态多态 work函数接口通过传参不同做不同的工作 #include "iostream"using namespace std;class person {public:person(){}vi…...
数据库-MySQL之数据库必知必会17-21章
第17章 组 合 查 询 创建组合查询 可用UNION操作符来组合数条SQL查询。利用UNION,可给出多条SELECT语句,将它们的结果组合成单个结果集。 **例子:**假如需要价格小于等于5的所有物品的一个列表,而且还想包括供应商1001和1002生产…...
mysql主从复制-redis集群扩容缩容、缓存优化(缓存更新策略、穿透,击穿,雪崩)、mysql主从搭建、django实现读写分离
基于Docker实现读写分离 1 redis集群扩容缩容 1.1 集群扩容 1.2 集群缩容 2 缓存优化 2.1 缓存更新策略 2.2 穿透,击穿,雪崩 3 mysql主从搭建 4 django实现读写分离 1 redis集群扩容缩容 1.1 集群扩容 # 6台机器,3个节点集群# 8台机器&am…...
docker部署kerberos,群晖nas中nfs开启kerberos校验
背景 nas开启nfs存储共享,默认情况下只能给IP/24做限制, 达不到安全效果 需要增加kerberos策略校验,并且持久化kerberos数据,避免容器重启丢失数据 环境描述 宿主机系统:CentOS Linux release 7.9.2009 (Core) Docker版本…...
【前端】数据行点击选择
前言 【前篇文章】说了,我们公司的核心价值就是让人越来越懒,能怎么便捷就怎么便捷,主打一个简单实用又快捷,为了实现这个目标,我看成这个列表陷入了深思在想,要不要子表的数据加载在点击这个行时,就可以展示数据,这样就不用每次都要点那个小圆圈啦。 查资料 这显然…...
网络安全技术
网络安全技术是一种保护网络系统免受攻击、破坏或未经授权访问的技术。它涵盖了一系列的方法和工具,旨在确保数据的完整性、可用性和保密性。以下是一些主要的网络安全技术: 1. 防火墙:防火墙是一种用于阻止未经授权的访问,同时允…...
这几款 idea 插件让效率起飞!
作者:苍何,前大厂高级 Java 工程师,阿里云专家博主,CSDN 2023 年 实力新星,土木转码,现任部门技术 leader,专注于互联网技术分享,职场经验分享。 🔥热门文章推荐…...
[FUNC]判断窗口在哪一个屏幕上
#Requires AutoHotkey v2.0#z:: { ToolTip "Notepad窗口所在显示屏是:" GetMonitor() } GetMonitor() {CoordMode("Mouse", "Screen"); MouseGetPos &mx, &myWinGetPos &mx, &my,,,"ahk_class Notepad"…...
Vue语音播报,不用安装任何包和插件,直接调用。
Vue语音播报功能可以通过使用浏览器提供的Web Speech API来实现。这个API允许你的应用程序通过浏览器朗读文本,不用安装任何包和插件,直接调用。以下是一个简单的介绍,演示如何在Vue中使用语音提示功能: 一、JS版本 <template…...
公网穿透和RTC
RTC RTC 是 Real-Time Communication 的简写,正如其中文名称 “即时通讯” 的意思一样,RTC 协议被广泛用于各种即时通讯领域,诸如: 在线教育;直播中的主播连麦 PK;日常生活的音视频电话;.....…...
uniapp 使用web-view外接三方
来源 前阵子有个需求是需要在原有的项目上加入一个电子签名的功能,为了兼容性和复用性后面解决方法是将这个电子签名写在一个新的项目中,然后原有的项目使用web-view接入这个电子签名项目; 最近又有一个需求,是需要接入第三方的…...
SQL Sever 复习笔记【一】
SQL Sever 基础知识 一、查询数据第1节 基本 SQL Server 语句SELECT第2节 SELECT语句示例2.1 SELECT - 检索表示例的某些列2.2 SELECT - 检索表的所有列2.3 SELECT - 对结果集进行筛选2.4 SELECT - 对结果集进行排序2.5 SELECT - 对结果集进行分组2.5 SELECT - 对结果集进行筛选…...
DLSS Swapper终极指南:三大智能矩阵,重新定义游戏性能优化
DLSS Swapper终极指南:三大智能矩阵,重新定义游戏性能优化 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 你是否曾为游戏卡顿而烦恼?当最新的3A大作在4K分辨率下帧率骤降࿰…...
个人创作者利器:AI净界RMBG-1.4,3秒完成以往30分钟的手动精修
个人创作者利器:AI净界RMBG-1.4,3秒完成以往30分钟的手动精修 1. 为什么你需要AI净界RMBG-1.4? 作为一名内容创作者,你是否经常遇到这些困扰: 拍摄的产品照片背景杂乱,需要花费大量时间手动抠图精心设计…...
精准定位CPU核心稳定性:CoreCycler单核心测试全指南
精准定位CPU核心稳定性:CoreCycler单核心测试全指南 【免费下载链接】corecycler Script to test single core stability, e.g. for PBO & Curve Optimizer on AMD Ryzen or overclocking/undervolting on Intel processors 项目地址: https://gitcode.com/gh…...
互联网大厂Java求职者面试全场景详解(含技术栈解析与问答)
互联网大厂Java求职者面试全场景详解(含技术栈解析与问答) 文章标签 Java SE, Jakarta EE, JVM, Spring Boot, Maven, 微服务, 消息队列, 互联网大厂面试, 求职招聘, 技术问答 文章简述 本文围绕互联网大厂Java求职者面试场景,设计了由严肃面…...
丹青幻境效果展示:宣纸底纹UI下生成图像与界面美学统一性视觉报告
丹青幻境效果展示:宣纸底纹UI下生成图像与界面美学统一性视觉报告 1. 设计理念与视觉定位 丹青幻境的设计理念源于传统东方美学与现代数字艺术的完美融合。这款基于Z-Image架构打造的数字艺术创作工具,彻底摒弃了传统AI工具冰冷的技术感,将…...
Python入门第6章:字典(键值对数据结构)
Python入门第6章:字典(键值对数据结构) 大家好,欢迎来到Python入门系列的第6章内容!在前5章里,我们学会了变量、数据类型、运算符、if语句等基础知识点,也接触了列表、元组这两种序列数据结构—…...
【限时开源】Polars 2.0清洗模板库V1.0发布:含金融时序对齐、电商ID映射、日志正则归一化等9大高复用Pipeline
第一章:Polars 2.0大规模数据清洗技巧入门到精通教程 Polars 2.0 是专为高性能、内存安全与并行计算设计的 DataFrame 库,其惰性执行引擎与零拷贝语义使其在处理 GB 级别结构化数据时显著优于 Pandas。本章聚焦真实场景下的数据清洗实践,涵盖…...
成为技术专家的捷径?不,只有长期主义的坚持
在软件测试领域,我们常常被一种“速成”的幻象所包围。铺天盖地的培训广告承诺“三个月精通自动化测试”、“六周成为性能测试专家”,各种“一招鲜”的测试工具和“万能”的测试框架被包装成通往成功的捷径。对于身处其中、渴望突破职业瓶颈的测试工程师…...
MStar-Bin-Tool-Master中文版|晨星芯片BIN固件解包/封包工具(适配机顶盒与智能电视)
温馨提示:文末有联系方式工具简介 MStar-Bin-Tool-Master中文增强版是一款专为晨星(MStar)系列主控芯片设计的固件解析与重构工具,全面支持主流机顶盒与智能液晶电视所用BIN格式刷机包,提供直观易用的图形化操作界面&a…...
时间/金额转换
公式:大头 总数值 / 限制(除数)剩余 总数值 % 限制(除数)例如要将95分钟拆成小时分钟的形式60分钟1小时,那么这60就是限制小时 95 / 60分钟 95 % 60...
