数据结构-带头双向循环链表

文章目录

    • 一.头结点
    • 二.双链表
      • 1·双链表的概念与结构
      • 2.与单链表相比
    • 三.循环链表
      • 1.关于循环链表
      • 2.循环链表的优点
    • 四.带头双向循环链表
      • 1.带头双向循环链表
      • 2.结构图
      • 3.实现
    • 五.代码一览


一.头结点

在链表中设置头结点的作用是什么

标识链表:头结点是链表的特殊节点,它的存在能够明确标识出这是一个链表。在链表中,头结点通常不包含任何数据,它的主要作用是作为链表的入口,使得链表的操作更加方便。
简化操作:头结点的存在可以简化链表的操作。例如,当我们需要遍历整个链表时,只需要从头结点开始即可,无需关心链表的起始位置。同时,头结点的存在也使得在链表末尾插入或删除节点等操作更加方便。
提高效率:头结点的存在可以提高链表操作的效率。由于头结点是链表的第一个节点,因此在遍历链表时,我们无需担心指针的移动方向问题。同时,由于头结点在链表中的特殊位置,当需要访问链表的第一个元素时,可以通过直接访问头结点来获取,无需遍历整个链表。

在这里插入图片描述

二.双链表

1·双链表的概念与结构

概念:双链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针双向链接次序实现的。

结构图:
在这里插入图片描述

2.与单链表相比

双向性:双链表支持在每个节点上存储前驱节点和后继节点的指针,使得在任何节点上都可以方便地找到其前驱节点和后继节点。而单链表只能通过遍历整个链表来查找特定节点的下一个节点或上一个节点,效率较低。
插入和删除操作更高效:由于双链表支持双向链接,因此在插入和删除操作中,双链表只需要重新调整相关的指针即可,而不需要像单链表那样需要遍历整个链表。这使得双链表的插入和删除操作更高效。

三.循环链表

1.关于循环链表

循环链表是一种特殊的链表,其中最后一个节点指向第一个节点,即起始节点。起始节点充当列表开头的参考点。

(1)遍历时,可以从任何节点开始并以任何方向向前或向后遍历列表,直到到达开始的同一节点。
(2)循环链表没有开始也没有结束。
(3)在循环链表中,最后一个节点地址部分保存第一个节点的地址,从而形成一个循环链状结构。

(4).结构图:
在这里插入图片描述

2.循环链表的优点

(1)内存利用率是循环链表的共同优势之一
与线性数据结构不同,循环链表可以让人有效地使用内存,因为链表的大小动态增加或减少,因此不会浪费内存。此外,无需预先分配内存。
(2)实施
由于能够利用内存和易于数据操作,像堆栈和队列这样的线性数据结构通常可以使用链表轻松实现。
(3)易于数据操作
可以有效地处理循环链表的插入和删除,而无需重新构造链表。插入或删除元素后无需移动元素,只需更新下一个指针中存在的地址。

四.带头双向循环链表

1.带头双向循环链表

结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了,后面我们代码实现了就知道了。

2.结构图

在这里插入图片描述

3.实现

思路:
(1)利用结构体存储数据和指针(结构体能够存储不同类型的数据)
(2)通过malloc函数进行扩容
(3)通过多条件实现
(4)我们实现初始化、打印、扩容、尾插、头插等函数
框架:
结构体的创建、一些定义等
List.h

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}ListNode;

Test.c

void Test() {ListNode* plist = ListInit()初始化,头结点不存储数据;}
int main() {Test();return 0;
}

函数实现:
(1)扩容函数:
返回值:一个结构体指针
参数:传来的数据
通过malloc函数实现扩容,并将扩容后的指针置空和存储传来的数据
代码:

ListNode* BuyListNode(LTDataType x) {//扩容ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));//扩容newnode->data = x;//存储数据newnode->next = NULL;//指针置空newnode->prev = NULL;return newnode;//返回指针
}

(2)初始化函数
我们开始要初始化一个头结点(不存储数据)
返回:一个指针(我们的头结点)
代码:

ListNode* ListInit() {//初始化ListNode* phead = BuyListNode(0);//第一个数据不打印phead->next = phead;//只有一个头结点,因为是双向循环链表,自己连接自己phead->prev = phead;return phead;
}

如图:
在这里插入图片描述
打印函数
代码:

void ListPrint(ListNode* phead) {assert(phead);//判断是否为空//初始条件ListNode* cat = phead->next;//打印出头结点next指向的结构体开始//结束条件while (cat!= phead)//当打印完一次后就会遇上同结点,此时结束打印{printf("%d ", cat->data);//迭代条件cat = cat->next;}printf("\n");
}

(3)尾插函数
我们要将一个数据尾插进去
第一步:找到这个链表的结尾处,我们可以通过头结点找到
第二步:我们重新将结尾处结构体的next指向尾插进来的结构体,再将尾插进来的结构体的prev指向结尾处的结构体,再再将尾插进来的结构体的next指向头结点,再再再将头结点的perv指向尾插进来的结构体
插前:
在这里插入图片描述
插后:
在这里插入图片描述
代码:

void ListPushBack(ListNode* phead, LTDataType x) {//尾插assert(phead);//判断是否为空ListNode* newnode = BuyListNode(x);//扩容ListNode* cat = phead->prev;//找到尾结点并保存//重新连接cat->next = newnode;newnode->prev = cat;phead->prev = newnode;newnode->next = phead;
}

检查:
尾插 1 、2 、3

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);

运行结果:
在这里插入图片描述
(4)头插函数
我们要将一个数据尾插进去
第一步:通过头结点找到第一个存储数据的点
第二步:我们重新将第一存储数据的结点处结构体的prev指向头插进来的结构体,再将头插进来的结构体的next指向第一个存储数据的结构体,再再将头插进来的结构体的prtv指向头结点,再再再将头结点的next指向头插进来的结构体

插前:
在这里插入图片描述
插后:
在这里插入图片描述
代码:

void ListPushFront(ListNode* phead, LTDataType x) {//头插assert(phead);ListNode* newnode = BuyListNode(x);ListNode* cat = phead->next;//找到头结点并保存//重新连接cat->prev = newnode;newnode->next = cat;phead->next = newnode;newnode->prev = phead;
}

检查:

头插 0
ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);

运行结果:
在这里插入图片描述
(5)头删函数
我们想要删除第一个数据
第一步:通过头结点找到第一个存储数据的结点,再通过第一个存储数据的结点来找到第二个存储数据的结点
第二步:将第一个存储数据的结点释放掉,然后再将第二个存储数据的结点的prev指向头结点,再再头结点的next指向第二个存储数据的结点
删前:
在这里插入图片描述
删后:
在这里插入图片描述

代码:

void ListPopFront(ListNode* phead) {//头删assert(phead);assert(phead->next != phead);//ListNode* cat = phead->next->next;//通过第一个存储结点找到第二个存储的结点并保存free(phead->next);//释放掉phead->next = NULL;//并置空//重新连接cat->prev = phead;phead->next = cat;}

检查:
头删一个数据

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);
ListPopFront(plist);

运行结果:

在这里插入图片描述
(6)尾删函数
我们将最后一个结点删除
第一步:通过头结点来找到最后一个结点,再通过最后一个结点来找到倒数第二个结点
第二步:将最后一个结点释放掉,再将倒数第二个结点的next指向头结点,再再将头结点的prev指向倒数第二个结点
删前:
在这里插入图片描述
删后:
在这里插入图片描述
检查
尾删一个数据

ListNode* plist = ListInit();
ListPushBack(plist, 1);
ListPushBack(plist, 2);
ListPushBack(plist, 3);
ListPushFront(plist, 0);
ListPopFront(plist);
ListPopBack(plist);
ListPrint(plist);

运行结果:
在这里插入图片描述

五.代码一览

List.h:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType data;
}ListNode;ListNode* ListInit();//初始化
void ListDestory(ListNode* phead);//清空
void ListPrint(ListNode* phead);//打印void ListPushBack(ListNode* phead, LTDataType x);//尾插
void ListPushFront(ListNode* phead, LTDataType x);//头插
void ListPopFront(ListNode* phead);//头删
void ListPopBack(ListNode* phead);//尾删

List.c:

#define _CRT_SECURE_NO_WARNINGS
#include"List.h"ListNode* BuyListNode(LTDataType x) {//扩容ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;newnode->prev = NULL;return newnode;
}ListNode* ListInit() {//初始化ListNode* phead = BuyListNode(0);phead->next = phead;phead->prev = phead;return phead;
}void ListPrint(ListNode* phead) {assert(phead);//初始条件ListNode* cat = phead->next;//结束条件while (cat!= phead){printf("%d ", cat->data);//迭代条件cat = cat->next;}printf("\n");
}
void ListPushBack(ListNode* phead, LTDataType x) {//尾插assert(phead);ListNode* newnode = BuyListNode(x);ListNode* cat = phead->prev;cat->next = newnode;newnode->prev = cat;phead->prev = newnode;newnode->next = phead;
}
void ListPushFront(ListNode* phead, LTDataType x) {//头插assert(phead);ListNode* newnode = BuyListNode(x);ListNode* cat = phead->next;cat->prev = newnode;newnode->next = cat;phead->next = newnode;newnode->prev = phead;
}
void ListPopFront(ListNode* phead) {//头删assert(phead);assert(phead->next != phead);ListNode* cat = phead->next->next;free(phead->next);phead->next = NULL;cat->prev = phead;phead->next = cat;}
void ListPopBack(ListNode* phead) {//尾删assert(phead);assert(phead->prev != phead);ListNode* cat = phead->prev->prev;free(phead->prev);phead->prev = NULL;cat->next = phead;phead->prev = cat;
}

Test.c

void Test() {ListNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushFront(plist, 0);ListPopFront(plist);ListPopBack(plist);ListPrint(plist);}int main() {Test();return 0;
}

以上就是全部代码了
还有一些查改等接口函数没实现,感兴趣的可以去试试

以上就是我的分享了,如果有什么错误,欢迎在评论区留言。
最后,谢谢大家的观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/190558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mongodb安装及其使用

1.Linux系统上安装Mongodb 在usr/local文件夹下创建mongo文件夹 下载mongodb包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-6.0.5.tgz解压mongodb tar -zxvf mongodb-linux-x86_64-rhel70-6.0.5.tgz更改文件夹的名字 mv mongodb-linux-x86_64-rh…

RCE绕过

1.[SCTF 2021]rceme 总结下获取disabled_funciton的方式 1.phpinfo() 2.var_dump(ini_get(“disable_functions”)); 3.var_dump(get_cfg_var(“disable_functions”)); 其他的 var_dump(get_cfg_var(“open_basedir”)); var_dump(ini_get_all()); <?php if(isset($_POS…

蓝桥杯算法心得——小郑躲太阳(思维推导)

大家好&#xff0c;我是晴天学长&#xff0c;一道与平时的题型截然不同的题型&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .小郑躲太阳 问题描述 小郑一觉醒来发现起晚啦!现在需要从家里飞速前往公司…

B026-MySQL基础

目录 数据库概述数据库概念数据库的由来和发展常见的关系型数据库服务器&#xff08;DBMS&#xff09;SQL概述表的概念 数据库的安装与配置安装启动和连接MySQL启动MySQL服务连接MySQL MySQL图形化管理软件-Navicat数据库安装失败解决方案 MySQL数据库操作数据库操作和存储引擎…

8.ROS的TF坐标变换(二):动态坐标变换、多坐标变换代码讲解(以LIO-SAM为例)

目录 1 ROS的动态坐标变换及代码解释 1.1 什么是ROS的动态坐标变换 1.2 CMakeLists.txt、package.xml基础配置 1.3 发布方代码实现 1.4 接收方代码实现 2 ROS的多坐标变换及代码解释 2.1 什么是ROS的多坐标变换 2.2 发布方代码实现 2.3 接收方代码实现 3 L…

图解系列--功能追加协议,构建Web内容

功能追加协议 1.消除 HTTP 瓶颈的 SPDY 1.1.HTTP 的瓶颈 使用 HTTP 协议探知服务器上是否有内容更新&#xff0c;就必须频繁地从客户端到服务器端进行确认。如果服务器上没有内容更新&#xff0c;那么就会产生徒劳的通信。 若想在现有 Web 实现所需的功能&#xff0c;以下这些…

线程与多线程编程

1. 线程 1.1 概念 线程又可以称为轻量级进程 &#xff0c;在进程的基础上做出了改进。 一个进程在刚刚启动时&#xff0c;做的第一件事就是申请内存和资源&#xff0c;进程需要把依赖的代码和数据&#xff0c;从磁盘加载到内存中这件事是比较耗费时间的&#xff0c;有的业务…

matlab simulink 永磁同步电机PI调速控制

1、内容简介 略 27-可以交流、咨询、答疑 2、内容说明 永磁同步电机调速控制 永磁同步电机PI调速控制 永磁同步电机PI调速控制、PMSM 3、仿真分析 略 4、参考论文 略 链接&#xff1a;https://pan.baidu.com/s/1AAJ_SlHseYpa5HAwMJlk1w 提取码&#xff1a;rvol 路…

科研者的福利!一个集论文、代码、数据集为一体的网站

Papers with Code 是一个总结了机器学习论文及其代码实现的网站。大多数论文都是有GitHub代码的。这个网站最好的地方就是对机器学习做了任务分类&#xff0c;检索对应的模型非常方便。早在18年Paper With Code创立时就轰动一时&#xff0c;仅创立一年就被Facebook收购。 Pape…

Spring AOP记录接口访问日志

Spring AOP记录接口访问日志 介绍应用范围组成通知&#xff08;Advice&#xff09;连接点&#xff08;JoinPoint&#xff09;切点&#xff08;Pointcut&#xff09;切面&#xff08;Aspect&#xff09;引入&#xff08;Introduction&#xff09;织入&#xff08;Weaving&#x…

Linux--初识和基本的指令(3)

目录 1.前言 1.指令 1.1 cat指令 1.2 echo指令 1.3 more 指令 1.4 less指令 1.5 什么时候使用less和more 1.6 head指令 1.7 tail指令 1.8 wc指令 1.9 与时间相关的指令 1.9.1 date指令 1.9.2 cal指令 1.10 16.find指令&#xff1a;&#xff08;灰常重要&#x…

千梦网创:熟悉抖音内容创作的切入方式

因为身边抖音网红的资源比较近&#xff0c;所以虽然一直没有露脸去做短视频运营&#xff0c;但是最近也是跟随朋友一起开始了短视频的学习之路。 在参观过一些“超级直播间”之后&#xff0c;我们敲定了未来的两个盈利方向&#xff0c;这两个方向可以将我们身边的资源极致利用…

MyBatis-逆向工程

1.简单生成 1.添加依赖和插件 <dependencies><!-- MyBatis核心依赖包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><!-- MySQL驱动…

金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC]

文章目录 金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 金蝶Apusic应用服务器deployApp接口任意文件上传漏洞复现 [附POC] 0x01 前言 免责声明…

【前端】-【electron】

文章目录 介绍electron工作流程环境搭建 electron生命周期&#xff08;app的生命周期&#xff09;窗口尺寸窗口标题自定义窗口的实现阻止窗口关闭父子及模态窗口自定义菜单 介绍 electron技术架构&#xff1a;chromium、node.js、native.apis electron工作流程 桌面应用就是…

常见的攻击防护

只做模拟机器使用&#xff0c;不使用真实机器 目录 一、 DHCP饿死和防护应对措施.................................. 1 1&#xff0c; 实验拓扑&#xff1a;...................................................... 2 2&#xff0c; 实验配置............................…

Web自动化测试怎么做?Web自动化测试的详细流程和步骤

1.什么是web自动化测试 自动化&#xff08;Automation&#xff09;是指机器设备、系统或过程&#xff08;生产、管理过程&#xff09;在没有人或较少人的直接参与下&#xff0c;按照人的要求&#xff0c;经过自动检测、信息处理、分析判断、操纵控制&#xff0c;实现预期的目标…

opencv阈值处理

阈值处理 二值化 自适应阈值 OTSU二值化

latex表格中内容过多如何换行【已解决】

最近在写论文的时候放了一个表格&#xff0c;但是表格看起来特别大&#xff0c;因为想让某些内容多的单元格完成换行操作 首先在main.tex引入makecell包 \usepackage{makecell} 然后回到表格找到你想换行的单元格&#xff0c;把\makecell{}加进去&#xff0c;然后在需要换行的…

基于物联网技术的基站能耗监控解决方案-安科瑞 蒋静

摘 要&#xff1a;随着社会的不断发展和进步&#xff0c;人们对通信基站的需求增加。随着通信基站大规模的建设和使用&#xff0c;基站内部的电源情况、供电安全保障或节能减排等问题&#xff0c;仍然是基站建设的着重问题。不管是建设者还是使用者&#xff0c;都应当注重用电安…