双链表详解(初始化、插入、删除、遍历)(数据结构与算法)

news2024/11/29 14:52:06

1. 单链表与双链表的区别

单链表(Singly Linked List)和双链表(Doubly Linked List)是两种常见的链表数据结构,它们在节点之间的连接方式上有所区别。

单链表:

  1. 单链表的每个节点包含两个部分:数据域和指针域。
  2. 数据域存储节点的值或数据。
  3. 指针域存储指向下一个节点的指针,即单链表的指针指向下一个节点。
  4. 单链表只能从头节点开始顺序访问,通过指针域进行节点之间的连接。
  5. 单链表只能单向遍历,即只能从头节点开始,沿着指针域逐个访问下一个节点。
  6. 无法逆向检索,有时候不太方便

双链表:
7. 双链表的每个节点包含三个部分:数据域、指向前一个节点的指针和指向下一个节点的指针。
8. 数据域存储节点的值或数据。
9. 前驱指针指向前一个节点,后继指针指向下一个节点。
10. 双链表可以双向遍历,既能从头节点顺序遍历,也可以从尾节点逆序遍历。
11. 双链表相较于单链表需要额外存储指向前一个节点的指针,因此会在空间上占用更多的内存。
12. 可进可退,存储密度更低一点

单链表和双链表的选择取决于需要解决的问题和应用场景。对于只需要顺序遍历或仅从头部开始操作的情况,单链表可能是更简洁和高效的选择。但对于需要在两个方向上遍历或在任意位置插入或删除节点的情况,双链表就更有优势了。

双链表: 初始化、插入、删除、遍历


2. 双链表的初始化(带头结点)

//初始化双链表 
typedef struct DNode		//定义双链表结点类型
{
	Elemtype data;			//数据域
	struct DNode *prior, *next;  //前驱和后继指针
}DNode, *DLinkList;	

bool InitDLinkList(DLinkList &L)
{
	L = (DNode *) malloc(sizeof(DNode));		//分配一个头结点
	if(L == NULL)		//内存不足,分配失败
		return false;
	L->prior = NULL;		//头结点的prior永远指向NULL
	L->next = NULL;			//头结点之后暂时还没有结点
	return true;	
}
void testDLinkList()
{
	DLinkList L; //初始化双链表
	InitDLinkList(L);
	//后续代码......
}

//判断双链表是否为空(带头结点)
bool Empty(DLinkList L) 
{	
	if(L->next == NULL)
		return true;
	else
		return false;
}

3. 双链表的插入

在双链表中插入节点需要更新前驱节点和后继节点的指针连接,操作相对比较复杂。

  1. 首先,创建一个新节点,并设置它的数据值。
  2. 找到要插入位置的前驱节点。
  3. 将新节点的前驱指针指向前驱节点。
  4. 将新节点的后继指针指向前驱节点的后继节点。
  5. 更新前驱节点的后继指针指向新节点。
  6. 如果新节点的后继节点非空,将后继节点的前驱指针指向新节点。
  • 若结点在双链表插入数据元素e,且p结点有后继结点,如下图所示。
    在这里插入图片描述
    程序设计如下:
//在p结点之后插入s结点
bool InsertNextDNode(DNode *P, DNode *s)
{
	s->next = p->next;	//将结点*s插入到结点*p之后, 如上图步骤1
	p->next->prior = s;  //如上图步骤2
	s->prior = p;     //如上图步骤3
	p->next = s;      //如上图步骤4
}

在这里插入图片描述

  • 如果p是最后一个结点,会发生什么?

p->next->prior = s; //如上图步骤2 这一行代码将出现问题 p->next指向的是NULL, 改进如下:

在这里插入图片描述
程序设计如下:注意修改指针时要注意顺序!!!

//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s)
{
	if (p == NULL || s == NULL) //非法参数
		return false;
	s->next = p->next;        //  (*)
	if(p->next != NULL)
	{
		p->next->prior = s;  //如果p结点有后继结点,就回到了上一个情况
	}
	s->prior = p;	  //蓝色箭头操作
	p->next = s;      //橙色箭头操作    (**)    
	return true;  //插入成功
}
  • 指针顺序不能错! 假如 (*) 与(**)行交换。 那么就会出现如下图情况,p指针next与s->next指向同一位置。
    在这里插入图片描述
    用后插操作实现结点插入有什么好处?
  • 按位序插入前插操作:效果等同于 ====> 可以先找到前驱结点,再对其做后插操作
  • 其他插入操作,都可以转换成后插操作

在这里插入图片描述


4. 双链表的删除

在双链表中删除节点的操作相对比较复杂,因为我们需要维护前驱节点和后继节点之间的指针连接。
以下是删除双链表中某个节点的一般步骤:

  1. 首先,找到要删除的节点。
  2. 如果要删除的节点是头节点,将头节点指针指向下一个节点,并更新下一个节点的前驱指针为 nullptr。
  3. 如果要删除的节点是尾节点,将前一个节点的后继指针设为 nullptr,并更新尾节点指针为前一个节点。
  4. 如果要删除的节点既不是头节点也不是尾节点,将前一个节点的后继指针指向要删除节点的后一个节点,将后一个节点的前驱指针指向要删除节点的前一个节点。
  5. 释放要删除的节点的内存空间。
//删除p的后继结点q, 如下图所示
p->next = q->next;
q->next->prior = p;
free(q);

在这里插入图片描述


在实际使用中,应该确保要删除的节点在链表中确实存在。如果删除的节点不存在于链表中,需要根据具体的需求进行错误处理。同时,删除节点后必须确保释放相应的内存空间,以防止内存泄漏问题的发生。

删除q结点

在这里插入图片描述

将 p 结点的next指针,指向q结点的后继结点。

在这里插入图片描述

释放 q 结点空间

在这里插入图片描述

3.1 删除p结点的后继结点

//删除p结点的后继结点
bool DeleteNextDNode(DNode *p)
{
	if(p==NULL)		
		return false;
	DNode *q = p->next;			//找到p的后继结点
	if(q==NULL)
		return false;		//p没有后继结点
	p->next = q->next;
	if(q->next != NULL)		//q结点不是最后一个结点
		q->next->prior = p;	
	free(q);		//释放结点空间
	return true;	//删除成功	
}

3.2 销毁一个双链表

//销毁一个双链表
void DestoryList(DLinkList &L)
{
	//循环释放各个数据结点
	while(L->next != NULL)    //判断头结点是否有后继结点,直到头结点后再无其他结点结束循环
	{
		DeleteNextDNode(L);    //删除p结点的后继结点
	}
	free(L);	//释放头结点
	L = NULL;		//头指针指向NULL	
}

5. 双链表的遍历

4.1 后向遍历

while(p != NULL)
{
	//对结点p做相应处理,如打印
	p = p->next;
}

4.2 前向遍历

while(p != NULL)
{
	//对结点p做响应处理
	p = p->prior;
}

4.3 前向遍历(跳过头结点)

while(p->prior != NULL)  //当前驱为NULL时,此时遍历到第一个结点,退出循环,跳过了头结点。
{
	//对结点p做相应处理
	p = p->prior;
}

双链表不可随机存取,按位查找、按值查找操作都只能用遍历的方式实现,时间复杂度为O(n)


6. 知识点回顾

在这里插入图片描述

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

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

相关文章

利用大语言模型(LLM )提高工作效率

日常工作就是面向 google/ 百度编程,除了给变量命名是手动输入,大多时候就是通过搜索引擎拷贝别人的代码,或者找到旧项目一段代码拷贝过来使用。这无疑是开发人员的真实写照;然而,通过搜索引擎搜索答案,无疑…

【嵌入式开发工具】STM32+Keil实现软件工程搭建与开发调试

本篇文章介绍了使用Keil来对STM32F103C8芯片进行初始工程搭建,以及开发与工程调试的完整过程,帮助读者能够在实战中体会到Keil这个开发环境的使用方法,了解一个嵌入式工程从无到有的过程,并且具备快速搭建一个全新芯片对应最小软件…

CMU/MIT/清华/Umass提出生成式机器人智能体RoboGen

文章目录 导读1. Introduction2. 论文地址3. 项目主页4. 开源地址5. RoboGen Pipeline6. Experimental Results作者介绍Reference 导读 CMU/MIT/清华/Umass提出的全球首个生成式机器人智能体RoboGen,可以无限生成数据,让机器人7*24小时永不停歇地训练。…

CVE-2023-21839 weblogic rce漏洞复现

文章目录 一、漏洞影响版本二、漏洞验证三、启动反弹shell监听切换路径到jdk1.8 四、启动ldap服务五、使用CVE-2023-21839工具来进行攻击测试六、反弹shell 一、漏洞影响版本 CVE-2023-21839是Weblogic产品中的远程代码执行漏洞,由于Weblogic IIOP/T3协议存在缺陷&…

Python基础入门例程35-NP35 朋友的年龄是否相等(运算符)

最近的博文: Python基础入门例程34-NP34 除法与取模运算(运算符)-CSDN博客 Python基础入门例程33-NP33 乘法与幂运算(运算符)-CSDN博客 Python基础入门例程32-NP32 牛牛的加减器(运算符)-CSD…

【源码解析】聊聊SpringBean是如何初始化和创建

我们知道通过类进行修复不同的属性,比如单例、原型等,而具体的流程是怎么样的呢,这一篇我们开始从源码的视角分析以下。 刷新方法 在刷新容器中有一个方法,其实就是 Bean创建的过程。 finishBeanFactoryInitialization(beanFact…

大数据分析:基于时间序列的股票预测于分析 计算机竞赛

1 简介 Hi,大家好,这里是丹成学长,今天向大家介绍一个大数据项目 大数据分析:基于时间序列的股票预测于分析 2 时间序列的由来 提到时间序列分析技术,就不得不说到其中的AR/MA/ARMA/ARIMA分析模型。这四种分析方法…

一篇文章带你学会MybatisPlus~

实现MybatisPlus的简单使用: 数据库准备部分: //创建名为mybatisPlus的数据库 create database mybatisPlus;//使用该数据库 use mybatisPlus;//创建user表 CREATE TABLE user( id bigint(20) NOT NULL COMMENT 主键ID , name varchar(30) DEFAULT NUL…

信道编码译码及MATLAB仿真

文章目录 前言一、什么是信道编码?二、信道编码的基本逻辑—冗余数据1、奇偶检验码2、重复码 三、编码率四、4G 和 5G 的信道编码1、卷积码2、维特比译码(Viterbi)—— 概率译码3、LTE 的咬尾卷积码4、LTE 的 turbo 码 五、MATLAB 仿真1、plo…

深度学习_9_图片分类数据集

散装代码: import matplotlib.pyplot as plt import torch import torchvision from torch.utils import data from torchvision import transforms from d2l import torch as d2ld2l.use_svg_display()# 通过ToTensor实例将图像数据从PIL类型变换成32位浮点数格式…

Win11系统下Oracle11g数据库下载与安装使用教程

文章目录 一、Oracle下载与安装1.1 解压安装包1.2 开始安装Oracle11g1.2.1 用户 1.3 测试数据库是否配置成功1.4 了解一下 Oracle相关服务1.5 了解Oracle体系结构 二、使用工具连接数据库2.1 PL/ SQL 连接本地oracle 三、PL/ SQL远程访问数据库3.1 可能踩坑问题(TNS…

10.MySQL事务(上)

个人主页:Lei宝啊 愿所有美好如期而遇 目录 前言: 是什么? 为什么? 怎么做? 前言: 本篇文章将会说明什么是事务,为什么会出现事务?事务是怎么做的? 是什么? 我…

python-列表推导式、生成器表达式

一、列表推导式 列表推导式:用一句话来生成列表 语法:[结果 for循环 判断] 筛选模式: 二、生成器表达式

python工具三星路由器远程命令执行漏洞

无人扶我青云志,我自踏雪至山巅;​倘若命中无此运,孤身亦可登昆仑 python工具 漏洞证明: 文笔生疏,措辞浅薄,望各位大佬不吝赐教,万分感谢。 免责声明:由于传播或利用此文所提供的…

JVM虚拟机:如何查看自己的JVM默认的垃圾回收器

只需要在程序运行的时候指定下面的参数就可以看到当前自己的JVM默认的垃圾回收器是什么?如下所示: 如上所示,默认使用的是G1回收器,这是我的电脑,因为我的电脑安装jdk的版本是1.9 如果你的jdk的版本是1.8,那…

一、技术选型(从零开始撸斗地主)

将心沉下来,构建一个自己属于自己的城堡。 最近准备搞一个能承载上万人同时在线的斗地主游戏。 技术选型 客户端:Unity3D 目前有俩个选项,unity3d,cocosCreator 思考了很久,最终决定选用自己擅长的框架来搞。 服务器&#xff…

什么是单片机?它是如何工作的?

一.单片机是什么? 家用电器包含各种各样的集成电路板。 在集成电路板上最重要的就是单片机(单片微型计算机)。它是一种集成电路芯片。 二.单片机的组成 2.1 CPU CPU的主要功能是运算和控制。2.2 ROM 1.是什么? ROM的全称是Re…

delphi7安装并使用皮肤控件

1、下载控件 我已经上传到云盘,存储位置 2、下载后并解压。 3、打开dephi7,File-Open,打开路径D:\LC\Desktop\vclskin2_XiaZaiBa\d7, 然后将 D:\LC\Desktop\vclskin2_XiaZaiBa\d7文件夹中所有后缀.dcu的文件复制粘贴到delphi安装路…

【2024最新】HBuilder X3.1.22【安装】零基础入门到精通,看完这一篇就够了【附安装链接】

软件下载 软件:HBuilder X版本:3.1.22语言:简体中文大小:278.95M安装环境:Win11/Win10/Win8/Win7硬件要求:CPU2.0GHz 内存4G(或更高)下载通道①百度网盘丨下载链接:https://pan.bai…

[计算机网络]认识“协议”

认识“协议” 文章目录 认识“协议”序列化和反序列化网络计算器引入Sock类设计协议编写服务端类启动服务端编写客户端类启动客户端程序测试 序列化和反序列化 在网络体系结构中,应用层的应用程序会产生数据,这个数据往往不是简单的一段字符串数据&…