数据结构初阶(c语言)-双向链表

这里首先纠正上篇文章一个错误,链表的一个有效数据点应该称为结点而不是节点。

一,双向链表的概念与结构

1.1概念与结构示意图

         我们所说的双向链表全称为带头双向循环链表,也就是说此链表带有哨兵位结点(不存放任何数据的结点,且为头结点)。图示结构如下:

         注意:这里的“带头”跟前面我们说的“头结点”是两个概念,实际前面的在单链表阶段称呼不严谨。

1.2双向链表结构代码

typedef int LTNDataType;
typedef struct ListNode
{LTNDataType val;struct ListNode* prev;struct ListNode* next;
}LTNode;

          prev为指向前一个结点的指针,next为指向后一个结点的指针,val为该结点中存储的数据。

二,实现双向链表的功能

2.1创建链表节点函数LTBuyNode

          由于我们的双向链表在没有存放任何数据时,还有一个哨兵位结点,所以我们需要先实现链表结点创建函数:

LTNode* LTBuyNode(LTNDataType x)
{LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));if (newnode == NULL){perror("buynode:");exit(1);}newnode->val = x;newnode->next = newnode->prev = newnode;return newnode;
}

          我们的双向链表为循环链表,所以在只有一个结点时,我们创建的新结点需要自己的两个前后指针均指向自己,以便实现我们的双向链表初始化。

2.2双向链表的初始化函数LTInit

         由于我们的哨兵位结点不存放有效数据,所以我们需要给初始结点直接返回一个存放数据为-1(无效数据)的结点,作为双向链表的初始结点:

LTNode* LTInit()
{LTNode* pcur = LTBuyNode(-1);return pcur;
}

 2.3双向链表的尾插函数LTPushBack

void LTPushBack(LTNode* phead, LTNDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);phead->prev->next = newnode;newnode->prev = phead->prev;newnode->next = phead;phead->prev = newnode;
}

         先创建一个新结点并用临时变量进行接收,下一步则是使尾节点的next指向我们的新结点,同时将新结点的prev指向先前的尾结点,接下来由于我们创建的新结点为当前的尾结点,所以我们需要让其next指针指向哨兵位结点,最后再使哨兵位结点的prev指向我们的新结点即完成我们的尾插函数。

2.4双向链表的头插函数LTPushStart

         这里需要注意,如果我们是直接将数据插到哨兵位前面,我们的方法实际上此时与尾插法无异,所以要实现头插,我们则需要将新结点直接插入到哨兵位结点的后面,从而实现头插:

void LTPushStart(LTNode* phead, LTNDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->prev = phead;newnode->next = phead->next;phead->next = newnode;newnode->next->prev = newnode;
}

          为了插入数据时的方便,我们先改变新插入结点的next与prev,这样不会对当前链表的结构产生影响,接下来我们便改变哨兵位结点的next与原哨兵位结点的next结点的prev,使其均指向我们创建的新结点,实现我们的头插法。

2.5判空函数LTEmpty

         当我们的链表只剩下哨兵位结点时,我们判定此时链表不存放任何有效数据,又由于我们此时只有一个结点,所以我们直接判定当前哨兵位结点的prev是否指向它自己即可:

bool LTEmpty(LTNode* phead)
{assert(phead);return (phead->next == phead);
}

2.6尾删函数LTDeltBack

         在进行尾删之前,我们也需要对链表进行判空,然后我们需要先用临时变量去保存尾结点的地址,同时改变尾结点的前结点的next,使其指向哨兵位,然后改变哨兵位结点的prev使其指向我们当前尾结点的前一个结点,最后释放尾结点即可:

void LTDeltBack(LTNode* phead)
{assert(phead && !LTEmpty(phead));LTNode* pcur = phead->prev;phead->prev->prev->next = phead;phead->prev = phead->prev->prev;free(pcur);pcur = NULL;
}

2.7头删函数LTDeltStart

         与尾删函数类似,也需要创建临时变量去记住要释放结点的位置,然后接下来步骤的思想与尾删基本相同:

void LTDeltStart(LTNode* phead)
{assert(phead && !LTEmpty(phead));LTNode* pcur = phead->next;phead->next = phead->next->next;phead->next->next->prev = phead;free(pcur);pcur = NULL;
}

2.8寻找目标位置函数LTFind

          与单链表的寻找方法基本一致,不过要注意终止条件应该是遍历到哨兵位结点时停止:

LTNode* LTFind(LTNode* phead,LTNDataType x)
{assert(phead && !LTEmpty(phead));LTNode* pcur = phead->next;while (pcur != phead){if (pcur->val == x){return pcur;}pcur = pcur->next;}printf("没有找到\n");return NULL;
}

2.9删除指定位置和向指定位置之后插入数据函数LTDeltDesBack与LTInserDesBack

         与单链表一样,但是这里向指定位置之前或之后插入数据方法一致,只是你实现之后插入后,如果想实现之前,只需要去用prev寻找上一结点即可:
LTDeltDesBack:

void LTDeltDesBack(LTNode* pos,LTNode* phead)
{assert(pos && (pos->next != phead));LTNode* pcur = pos->next;pos->next->next->prev = pos;pos->next = pos->next->next;free(pcur);pcur = NULL;
}

LTInserDesBack:

void LTInserDesBack(LTNode* pos,LTNDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);newnode->prev = pos;newnode->next = pos->next;newnode->next->prev = newnode;pos->next = newnode;
}

2.10销毁链表函数DestoLTN

void DestoLTN(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;LTNode* pcur1 = NULL;while (pcur != phead){pcur1 = pcur->next;free(pcur);pcur = pcur1;}free(phead);
}

三,顺序表与链表的对比

 

         当我们学习完顺序表与链表之后,下篇文章我们将介绍栈与队列的实现,在理解顺序表与链表功能的实现后,栈和队列的实现非常简单,仅仅只会有概念上不同的问题,我们下篇文章见。

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

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

相关文章

【Git多人协作开发】知识点总结

目录 知识点总结 1.创建dev分支开发 1.1在本地创建 1.1在远程创建(推荐) 2.远程分支和本地分支建立连接☞pull和push操作 2.1情况1 2.2情况2 2.3情况3 3.本地仓库对远程仓库的拉取pull操作 3.1情况1 3.2情况2 4.将开发分支的内容合并到远程m…

【Week-G5】适用于图像翻译的pix2pix模型-Pytorch版本

文章目录 1、基础知识1.1 图像翻译1.2 CGAN1.3 U-Net1.4 Pix2Pix 2、运行代码 🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 本次主要学习Pix2Pix网络,常用于图像翻译&#…

CVE-2020-7248 OpenWRT libubox标记二进制数据序列化漏洞(更新中)

提要 该文档会一直处于更新当中,当状态为完毕后,才是更新完成。由于网络上关于该漏洞原理的分析文档和资源实在是太少,而本人关于该方向也才是刚入门,能力有限,所以复现需要的时间较长,需要补充和学习的东西…

用Manim实现【多边形】类的实现——[上]

用Manim实现【多边形】类的实现——[上] Polygram内容是关于不同几何图形的分类,特别是涉及多边形(Polygon)及其扩展形式,比如多图形(Polygram)。在manim中有10中特征,接下来5种类及其特征的解…

搜维尔科技:Cyber​​glove通过其前所未有的柔性传感器技术,带来了多年的经验、专业知识和可靠性

Cyberglove 概述 新一代数据手套技术 MoCap 手套采用了原始 CyberGlove 产品 20 年经验所建立的技术,产生了改进的和新的特性、能力和设计,非常适合动作捕捉环境。 旧与新相遇, Cyberglove 通过其前所未有的柔性传感器技术,带来…

linux自动化构建工具--make/makefile

目录 1.make/makefile介绍 1.1基本认识 1.2依赖关系、依赖方法 1.3具体操作步骤 1.4进一步理解 1.5默认设置 1.6make二次使用的解释 1.7两个文件的时间问题 1.8总是被执行 1.9特殊符号介绍 1.make/makefile介绍 1.1基本认识 make是一个指令,makefile是一…

mysql面试(六)

前言 本章节详细讲解了一下mysql执行计划相关的属性释义,以及不同sql所出现的不同效果 执行计划 一条查询语句经过mysql查询优化器的各种基于成本和各种规则优化之后,会生成一个所谓的 执行计划,这个执行计划展示了这条查询语句具体查询方…

django 小型超市库存与销售管理系统-计算机毕业设计源码46608

摘 要 随着信息技术的快速发展,超市库存与销售管理面临着前所未有的挑战与机遇。为了提升超市的运营效率,优化库存管理,并增强销售数据的分析能力,我们基于Django框架设计并开发了一套小型超市库存与销售管理系统。该系统充分利用…

运算符的运算顺序

【单目算术位关系,逻辑三目后赋值】 ![在这里插入图片描述] (https://i-blog.csdnimg.cn/direct/e4c8f4e22b5044a48154bf7378e3b3b3.png)

php 做一个mqtt按钮,发布触发信号

在之前博客php 做一个文件下载服务器,得避免跨路径工具,安全很重要 中加了一个按钮,触发物联网设备返回数据。基于mqtt开发,如果想知道mqtt如何搭建,可以看我的博客【MQTT(1)】服务端的搭建 效…

机器学习 | 回归算法原理——多重回归

Hi,大家好,我是半亩花海。接着上次的多项式回归继续更新《白话机器学习的数学》这本书的学习笔记,在此分享多重回归这一回归算法原理。本章的回归算法原理基于《基于广告费预测点击量》项目,欢迎大家交流学习! 目录 一…

Air780EP模块 LuatOS开发-MQTT接入阿里云应用指南

简介 本文简单讲述了利用LuatOS-Air进行二次开发,采用一型一密、一机一密两种方式认证方式连接阿里云。整体结构如图 关联文档和使用工具:LuatOS库阿里云平台 准备工作 Air780EP_全IO开发板一套,包括天线SIM卡,USB线 PC电脑&…

产品经理-​统计数据是如何产生的(20)

在互联网当中,监测一个项目的实际情况,在产品当中,往往需要进行数据的监测,看用户的习惯,进而进行对产品进行优化,比如统计产品用户的一些行为,鼠标点击,鼠标hover,停留时长,进入,进出等 产品经理看到的数据统计一般是经历了下面几个阶段 数据埋点:这个阶段产品经理…

RK3568笔记四十三:MPU6050驱动开发(硬件I2C_3)

若该文为原创文章,转载请注明原文出处。 正点原子提供的I2C有测试ap3216c,SH3001等传感器,根据手册操作可以实现效果。 这里记录使用I2C3驱动MPU6050. 记录原因是前面有模拟I2C,但硬件如何使用,有点不是很清楚&#…

猫头虎分享:GPT-4o Mini VS GPT-3.5 Turbo 新旧对决,谁能拔得头筹?

GPT-4o Mini VS GPT-3.5 Turbo 🌟 新旧对决,谁能拔得头筹? 我们正在进入廉价语言模型的新时代 🚀 阅读时间:6分钟 摘要: 尽管 GPT-4o 功能强大,但我并不经常使用它。如果我正在寻找一个用于复…

【Hec-Ras】案例1:韩国Seung-gi stream稳定流/非稳定流模拟

Hec-Ras案例1:韩国Seung-gi stream 研究区域:Seung-gi stream(韩国)研究数据降水数据(Rainfall data) 步骤1:创建工程文件/打开已有工程文件步骤2:参数调整步骤2.1:数据导…

mysql 数据库空间统计sql

mysql 数据库空间统计 文章目录 mysql 数据库空间统计说明一、数据库存储代码二、查询某个数据库的所有表的 代码总结 说明 INFORMATION_SCHEMA Table Reference 表参考 information_schema是‌MySQL中的一个特殊数据库,它存储了关于所有其他数据库的元数据信息。…

D4.前缀和、差分

前缀和 一维前缀和(区间) 这样的好处是,可以以O(1)的时间复杂度来计算。而不是遍历O(n)。当读入数据非常大(>1000000)的时候,建议使用scanf()来读取数据,会比cin >> 快很多。在全局开…

享元模式(结构型)

目录 一、前言 二、享元模式 三、总结 一、前言 享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少大量细粒度对象的内存占用。它通过共享尽可能多的相同数据来节约内存空间。 享元模式由以下角色组成: Flyweight&…

「JavaEE」Spring MVC:基本操作1

🎇个人主页:Ice_Sugar_7 🎇所属专栏:JavaEE 🎇欢迎点赞收藏加关注哦! 简介 Spring Web MVC 是⼀个 Web 框架,简称为 Spring MVC MVC 是 Model View Controller 的缩写,它是软件工程…