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

【数据结构】带头双向循环链表的实现

🌇个人主页:平凡的小苏

📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情

🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html

🚀数据结构专栏:https://blog.csdn.net/vhhhbb/category_12211053.html

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!

 

       

1、带头循环双向链表

        我们在单链表中,有了next指针,这使得我们要查找下一节点的时间复杂度为O(1)。可是如果我们要查找的是上一节点的话,那最坏的时间复杂度就是O(n)了,因为我们每次都要从头开始遍历查找。

        为了克服单向性这一缺点,我们的老科学家们,设计出了双向链表。双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以再双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。

        既然单链表可以有循环链表,那么双向链表也可以有循环双向链表。(如下图所示)

2、双向循环链表函数接口的实现

2.1、双向循环链表的结构

typedef int LTDataType;
typedef struct ListNode
{LTDataType _data;//数据struct ListNode* _next;//后继指针struct ListNode* _prev;//前驱指针
}ListNode;

2.2、初始化双向循环链表

ListNode* ListCreate()
{ListNode* phead = (ListNode*)malloc(sizeof(ListNode));if (phead == NULL){perror("malloc Fail:");exit(-1);}phead->_next = phead;phead->_data = -1;phead->_prev = phead;return phead;
}

由于是带头循环链表,我们需要malloc一个头节点出来,当链表是空的时候,前驱指针和后继指针都指向头结点。

2.3、双向循环链表的插入 

// 创建返回链表的头结点.
ListNode* BuyListNode(LTDataType x)
{ListNode* newhead = (ListNode*)malloc(sizeof(ListNode));if (newhead == NULL){perror("malloc fail:");exit(-1);}newhead->_data = x;newhead->_next = NULL;newhead->_prev = NULL;return newhead;
}
//双链表插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newhead = BuyListNode(x);//该函数是创建新节点的函数ListNode* Prev = pos->_prev;Prev->_next = newhead;newhead->_prev = Prev;newhead->_next = pos;pos->_prev = newhead;
}

注:由于我们是在pos的前面插入一个结点,那么我们就应该保存上一个结点。

插入算法的具体操作步骤:

        1.Prev->_next = newhead;

        2.newhead->_prev = Prev;

        3.newhead->_next = pos;

        4.pos->_prev = newhead;

2.4、双向循环链表的删除操作

// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);//删除前pos不能为空assert(!ListEmpty(pos));//链表不为空才能删ListNode* ne = pos->_next;//保存pos位置的后一个结点pos->_prev->_next = ne;//删除结点的具体操作ne->_prev = pos->_prev;free(pos);//释放
}

2.5、双向循环链表的判空

bool ListEmpty(ListNode* pHead)
{assert(pHead);return pHead->_next == pHead;如果头结点的下一个结点也等于头结点的话那么链表为空
}

2.6、双向循环链表的打印

// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead){printf("%d ", cur->_data);cur = cur->_next;}printf("\n");
}

2.7、双向循环链表的销毁

// 双向链表销毁
void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead)//链表要遍历释放{ListNode* ne = cur->_next;free(cur);cur = ne;}free(pHead);pHead = NULL;
}

3、源代码

由于头插、头删、尾插、尾删可以用双向循环链表的插入和删除操作复用,这里直接放置源代码。

3.1、DList.c 

#include"DSList.h"
// 创建返回链表的头结点.
ListNode* BuyListNode(LTDataType x)
{ListNode* newhead = (ListNode*)malloc(sizeof(ListNode));if (newhead == NULL){perror("malloc fail:");exit(-1);}newhead->_data = x;newhead->_next = NULL;newhead->_prev = NULL;return newhead;
}
ListNode* ListCreate()
{ListNode* phead = (ListNode*)malloc(sizeof(ListNode));if (phead == NULL){perror("malloc Fail:");exit(-1);}phead->_next = phead;phead->_data = -1;phead->_prev = phead;return phead;
}
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newhead = BuyListNode(x);ListNode* tail = pHead->_prev;newhead->_prev = tail;tail->_next = newhead;newhead->_next = pHead;pHead->_prev = newhead;//ListInsert(pHead, x);
}
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* newhead = BuyListNode(x);ListNode* first = pHead->_next;newhead->_prev = pHead;pHead->_next = newhead;newhead->_next = first;first->_prev = newhead;//ListInsert(pHead->_next, x);
}
// 双向链表在pos的前面进行插入//判空
bool ListEmpty(ListNode* pHead)
{assert(pHead);return pHead->_next == pHead;
}
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListNode* tail = pHead->_prev;ListNode* prevtail = tail->_prev;prevtail->_next = pHead;pHead->_prev = prevtail;free(tail);//ListErase(pHead->_prev);
}
// 双向链表头删
void ListPopFront(ListNode* pHead)
{assert(pHead);assert(!ListEmpty(pHead));ListNode* first = pHead->_next;pHead->_next = first->_next;first->_next->_prev = pHead;free(first);//ListErase(pHead->_next);
}
//双链表插入
void ListInsert(ListNode* pos, LTDataType x)
{assert(pos);ListNode* newhead = BuyListNode(x);ListNode* Prev = pos->_prev;Prev->_next = newhead;newhead->_prev = Prev;newhead->_next = pos;pos->_prev = newhead;
}
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead){if (cur->_data == x){return cur;}cur = cur->_next;}return NULL;
}
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos)
{assert(pos);assert(!ListEmpty(pos));ListNode* ne = pos->_next;pos->_prev->_next = ne;ne->_prev = pos->_prev;free(pos);
}
// 双向链表打印
void ListPrint(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead){printf("%d ", cur->_data);cur = cur->_next;}printf("\n");
}
// 双向链表销毁
void ListDestory(ListNode* pHead)
{assert(pHead);ListNode* cur = pHead->_next;while (cur != pHead){ListNode* ne = cur->_next;free(cur);cur = ne;}free(pHead);pHead = NULL;
}

3.2、DList.h

#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
// 带头+双向+循环链表增删查改实现
typedef int LTDataType;
typedef struct ListNode
{LTDataType _data;struct ListNode* _next;struct ListNode* _prev;
}ListNode;// 创建返回链表的头结点.
ListNode* ListCreate();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
//判空
bool ListEmpty(ListNode* pHead);

好了!!!小编的分享到这里就结束了,有什么不足的地方请大佬多多指教!

相关文章:

【数据结构】带头双向循环链表的实现

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;别人可以拷贝我的模式&#xff0c;但不能拷贝我不断往前的激情 &#x1f6f8;C语言专栏&#xff1a;https://blog.csdn.net/vhhhbb/category_12174730.html &#x1f680;数据结构专栏&#xff…...

软件开发的权限系统功能模块设计,分享主流的九种常见权限模型

软件系统的权限控制几乎是非常常见且必备的&#xff0c;这篇文章整理下常见的九种模型&#xff0c;几乎基本够你用了&#xff0c;主流的权限模型主要有以下9种&#xff1a; 1、ACL模型 访问控制列表 2、DAC模型 自主访问控制 3、MAC模型 强制访问控制 4、ABAC模型 基于属性的访…...

CSS3-数据可视化

2D动画 - transform CSS3 transform属性允许你旋转&#xff0c;缩放&#xff0c;倾斜或平移给定元素。 Transform是形变的意思&#xff08;通常也叫变换&#xff09;&#xff0c;transformer就是变形金刚 常见的函数transform function有&#xff1a; 平移&#xff1a;transl…...

硬件系统工程师宝典(15)-----PCB上的EMC设计,“拿捏了”

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。上篇我们说到PCB常用的多层板叠层结构&#xff0c;综合成本、性能、需求考虑选择不同的叠层结构。今天我们来看看为提高EMC性能&#xff0c;在PCB设计…...

vue3滚动条滚动后元素固定

代码地址&#xff1a;https://gitee.com/zzhua195/easyblog-web-vuee Framework.vue 在这个布局组件中&#xff0c;监听main的滚动事件&#xff0c;获取滚动的距离&#xff0c;将它存入store&#xff0c;以便其它组件能够共享&#xff0c;监听到 <template><div c…...

新吲哚菁绿染料IR-825 NHS,IR825 NHS ester,IR825 SE,IR-825 活性酯,用于科研实验研究和临床

IR825 NHS理论分析&#xff1a;中文名&#xff1a;新吲哚菁绿-琥珀酰亚胺酯&#xff0c;IR-825 琥珀酰亚胺酯&#xff0c;IR-825 活性酯英文名&#xff1a;IR825 NHS&#xff0c;IR-825 NHS&#xff0c;IR825 NHS ester&#xff0c;IR825 SECAS号&#xff1a;N/AIR825 NHS产品详…...

GO语言--接口(interface)的定义及使用

接口定义 接口也是一种数据类型&#xff0c;它代表一组方法的集合。 接口是非侵入式的。即接口设计者无需知道接口被哪些类型实现&#xff0c;而接口使用者只需知道实现怎样的接口&#xff0c;并且无须指明实现哪一个接口。编译器在编译时就会知道哪个类型实现哪个接口&#…...

【Python语言基础】——Python MongoDB 查询

Python语言基础——Python MongoDB 查询 文章目录 Python语言基础——Python MongoDB 查询一、Python MongoDB 查询一、Python MongoDB 查询 筛选结果 在集合中查找文档时,您能够使用 query 对象过滤结果。 find() 方法的第一个参数是 query 对象,用于限定搜索。 实例 查找地…...

第十四届蓝桥杯模拟赛【第三期】Python

1 进制转换 问题描述   请找到一个大于 2022 的最小数&#xff0c;这个数转换成十六进制之后&#xff0c;所有的数位&#xff08;不含前导 0&#xff09;都为字母&#xff08;A 到 F&#xff09;。   请将这个数的十进制形式作为答案提交。 答案&#xff1a;2730 def ch…...

windows 下docker 安装clickhouse

docker 下载https://www.docker.com/products/docker-desktop/将下载下来的Docker Desktop Installer.exe文件双击进行安装即可&#xff0c;安装完成后&#xff0c;任务栏会出现一个蓝色的小鲸鱼图标&#xff08;注意安装完成后可能会重启系统&#xff09;Docker Desktop如果出…...

【华为OD机试真题 JAVA】TLV编码问题

标题:TLV编码问题 | 时间限制:1秒 | 内存限制:262144K | 语言限制:不限 TLV编码是按TagLengthValue格式进行编码的,一段码流中的信元用tag标识,tag在码流中唯一不重复,length表示信元value的长度,value表示信元的值,码流以某信元的tag开头,tag固定占一个字节,lengt…...

深度学习 Day26——使用Pytorch实现猴痘病识别

深度学习 Day26——使用Pytorch实现猴痘病识别 文章目录深度学习 Day26——使用Pytorch实现猴痘病识别一、前言二、我的环境三、前期工作1、设置GPU导入依赖项2、导入猴痘病数据集3、划分数据集四、构建CNN网络五、训练模型1、设置超参数2、编写训练函数3、编写测试函数4、正式…...

redis简单介绍

对于一名前端工程师&#xff0c;想要进阶成为全栈工程师&#xff0c;redis技术是我们一定需要掌握的。作为当前非关系型数据库Nosql中比较热门的key-value存储系统&#xff0c;了解redis的原理和开发是极其重要的。本文我会循序渐进的带领大家一步步认识redis&#xff0c;使用r…...

Understanding services:理解服务(Service)

文章目录背景1. 准备工作2. ros2 service list 命令3. ros2 service type 命令3.1 ros2 service list -t 命令4. ros2 service find 命令5. ros2 interface show 命令6. ros2 service call 命令参考官方文档&#xff1a; Understanding services背景 服务&#xff08;Service&…...

【链表OJ题(五)】合并两个有序链表

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录链表OJ题(五)1. 合并…...

C++ Primer第五版_第三章习题答案(1~10)

文章目录练习3.1练习3.2一次读入一行一次读入一个词练习3.3练习3.4大的字符串长度大的字符串练习3.5未隔开的隔开的练习3.6练习3.7练习3.8练习3.9练习3.10练习3.1 使用恰当的using 声明重做 1.4.1节和2.6.2节的练习。 // 1.4.1 #include <iostream>using std::cin; using…...

小样本学习

机器学习就是从数据中学习&#xff0c;从而使完成任务的表现越来越好。小样本学习是具有有限监督数据的机器学习。类似的&#xff0c;其他的机器学习定义也都是在机器学习定义的基础上加上不同的限制条件衍生出来。例如&#xff0c;弱监督学习是强调在不完整、不准确、有噪声、…...

python打包成apk界面设计,python打包成安装文件

大家好&#xff0c;给大家分享一下如何将python程序打包成apk文件&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 1、如何用python制作十分秒加减的apk 如何用python制作十分秒加减的apk&#xff1f;用法:. apk包放入apk文件目录,然后输入…...

pytorch转onnx踩坑日记

在深度学习模型部署时&#xff0c;从pytorch转换onnx的过程中&#xff0c;踩了一些坑。本文总结了这些踩坑记录&#xff0c;希望可以帮助其他人。 首先&#xff0c;简单说明一下pytorch转onnx的意义。在pytorch训练出一个深度学习模型后&#xff0c;需要在TensorRT或者openvin…...

极智AI | GPT4来了,ChatGPT又该升级了

欢迎关注我,获取我的更多经验分享 大家好,我是极智视界,本文介绍一下 GPT4来了,ChatGPT又该升级了,更多的是个人思考。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 从 ChatGPT 发布 (2022年11月30日) 到…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...