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

【数据结构与算法】什么是双向链表?并用代码手动实现一个双向链表

文章目录

  • 一、什么是双向链表
  • 二、双向链表的简单实现

在这里插入图片描述

一、什么是双向链表

我们来看一下这个例子:

在一个教室里,所有的课桌排成一列,如图
在这里插入图片描述

相信在你们的读书生涯中,老师肯定有要求你们记住自己的前后桌是谁。所以该例子中,老师就要求学生们记住自己的前后桌,其中坐在第一排的学生需要记住自己是第一排的学生以及自己的后桌是谁;最后一排的学生要记住自己的前桌是谁以及自己是最后一排的学生。如图:
在这里插入图片描述

这一列座位就相当于一个 双向链表

假如有一天,老师还没记住每个学生的名字,于是就问:这一列第三个人叫什么名字?这时就要从第一个学生开始数,例如从图中坐在第一个的 小5 开始数:第一个人是 小5,他的后桌是 小7;因此第二个人就是 小7,他的后桌是 小1;因此第三个人就是 小1 了。此时老师问 小1:你的前桌叫什么名字?你的后桌叫什么名字?

因为刚开始老师就让每个学生记住了自己的前桌以及后桌,所以此时 小1 能很快地告诉老师他的前桌是 小7,他的后桌是 小6。

但是,我们设想一下,如果是上一篇文章的 链表结构 的例子中,如果老师在得知了第三个人是 小1 以后,询问 小1 的前桌叫什么名字,小1 能回答上来吗?并不能,因为老师只让每个学生记住了自己的后桌,所以此时想要得知 小1 的前桌叫什么名字,只能这样:第三个学生叫 小1,那么他的前桌就坐在第二个位置,所以从第一个学生开始数,第一个学生是 小5,他的后桌是 小7;因此第二个学生就是 小7。当然本文举得例子中学生数量有点少,但一旦数量多起来了,每次问一个学生他的前桌叫什么名字的时候,都要从头开始数。

从中可以看出,让每个学生记住自己的前桌后桌是非常有必要的,因为在某些情况下,可以快速地解决问题。

上面讲了那么多,接下来我们就来看一下 双向链表 是什么样的,如图

在这里插入图片描述

可以看到,对比 链表结构,双向链表 多了一个指针 tail,它是指向最后一个元素的,就相当于例子中的学生记住了自己是最后一排。

双向链表与单链表基本相似,但是最大的区别在于双向链表在节点中除了指向下一节点的next指针外,还有指向前一节点的prev指针,这使得双向链表在可以在任意节点从头尾两个方向进行遍历,是“双向”的。

和单链表相比,双向链表在删除和查询等方面明显在操作上更具有灵活性,但是会消耗更多的内存,需要根据使用条件进行取舍。

java中的LinkedHashMap的本质即是一个双向链表。
在这里插入图片描述

二、双向链表的简单实现

修改原来的Node类,在里面添加一个新成员变量Node prev

/*** @Author:huang* @Date:2023-03-23 20:10* @Description:节点类*/
public class Node {//节点序号int num;//数据Object data;//下一个节点Node next;//上一节点Node prev;public Node(int num, Object data) {this.num = num;this.data = data;}@Overridepublic String toString() {return "Node{" +"num=" + num +", data=" + data +'}';}
}
  1. 添加
    添加与单向链表代码逻辑一样,但是新节点在添加时需要修改prev指针指向原来的尾节点。
    举个例子,对于无排序插入,原本有节点A,现在要插入一个B:
  • 找到A,然后让A.next指向B
  • 让B.prev指向A

而对于排序插入,就是原有节点A,C,要在中间插入B:

  • 找到A,让B.prev指向A
  • 让B.next指向A.next,也就是让B的next指向C
  • 让A.next.prev指向B,也就是让C的prev指向B
  • 让A.next指向B
/*** 添加节点到链表* @param node 要插入的节点*/
public void add(Node node) {Node temp = head;//遍历链表while (true) {if (temp.next == null) {break;}//不是尾节点就继续遍历下一个节点temp = temp.next;}//将尾节点指向即将插入的新节点temp.next = node;node.prev = temp;
}/*** 按顺序添加节点到链表* @param node 要插入的节点*/
public void addByOrder(Node node) {Node temp = head;//遍历链表while (true) {//如果链表到底了就直接插入if (temp.next == null) {temp.next = node;node.prev = temp;return;}else if (temp.next.num > node.num){//如果后一节点比当新节点大,就插入当前节点node.prev = temp;node.next = temp.next;temp.next.prev = node;temp.next = node;return;}else if (temp.next.num == node.num){//如果后一节点等于新节点,抛异常throw new RuntimeException("插入节点与已有节点序号重复!");}//如果后一节点比当前节点小,就继续遍历temp = temp.next;}
}
  1. 删除
    由于相对单链表,双向链表的节点可以自己找到上一节点,所以删除的时候可以直接找到要删除的节点进行操作。

举个例子,假设有节点A,B,C,现在要删除B:

  • 找到B,让B.prev.next=B.next,也就是让A的next指向C
  • 让B.next.prev=B.prev,也就是让C的prev指向A

如果要删除的节点已经是尾节点了,那就跟单链表一样了。

/*** 删除节点* @param num 要删除的节点编号*/
public void delete(int num) {Node temp = head;//判断链表是否为空if (temp.next == null) {throw new RuntimeException("链表为空!");}//遍历链表while (true) {//如果链表到底了if (temp.next == null) {throw new RuntimeException("编号为" + num + "的节点不存在!");}//如果找到了待删除节点的前一个节点if (temp.num == num) {//判断待删除节点是否为尾节点if (temp.next == null){temp.prev.next = null;}else {temp.prev.next = temp.next;temp.next.prev = temp.prev;}return;}//继续遍历下一节点temp = temp.next;}
}
  1. 修改,查询(与单链表一致)
    由于修改和查询与单链表基本一致,这里就不在赘述了,直接放代码:
/*** 展示链表*/
public void show() {//判断链表是否为空if (head.next == null) {throw new RuntimeException("链表为空!");}Node temp = head.next;//遍历链表while (true) {if (temp == null) {break;}System.out.println(temp.toString());temp = temp.next;}
}/*** 根据序号获取节点* @param num 要获取的节点序号* @return*/
public Node get(int num){//判断链表是否为空if (head.next == null) {throw new RuntimeException("链表为空!");}Node temp = head.next;//遍历链表while (true) {if (temp == null) {throw new RuntimeException("编号为" + num + "的节点不存在!");}if (temp.num == num) {return temp;}temp = temp.next;}
}/*** 修改节点* @param node 要更新的节点*/
public void update(Node node) {Node temp = head;//判断链表是否为空if (temp.next == null) {throw new RuntimeException("链表为空!");}//获取要更新的节点序号int nodeNum = node.num;//遍历链表while (true) {//如果已经遍历完链表if (temp == null) {throw new RuntimeException("编号为" + temp.num + "的节点不存在!");}//如果找到了该节点if (temp.num == nodeNum) {temp.data = node.data;return;}//继续遍历下一节点temp = temp.next;}
}

相关文章:

【数据结构与算法】什么是双向链表?并用代码手动实现一个双向链表

文章目录一、什么是双向链表二、双向链表的简单实现一、什么是双向链表 我们来看一下这个例子: 在一个教室里,所有的课桌排成一列,如图 相信在你们的读书生涯中,老师肯定有要求你们记住自己的前后桌是谁。所以该例子中&#x…...

23种设计模式

参考链接: 【狂神说Java】通俗易懂的23种设计模式教学(停更)_哔哩哔哩_bilibili 23种设计模式【狂神说】_狂神说设计模式_miss_you1213的博客-CSDN博客 1. 单例模式 参考链接: 【狂神说Java】单例模式-23种设计模式系列_哔哩哔哩…...

20美刀一个月的ChatGPT架构师,性价比逆天了

文章目录20美刀一个月的ChatGPT架构师,性价比逆天了1.角色设定2.基本描述3.解决方案4.物理网络蓝图5.系统集成接口5.1 系统集成接口设计5.1.1 前端服务器与后端服务器接口:5.1.2 后端服务器与去背景处理服务接口:5.2 系统集成接口展示6.部署环…...

海门区教育科学规划课题2020年度成果鉴定书

海门区教育科学规划课题2020年度成果鉴定书 课题编号:HMGZ2020007 课题名称 中学历史核心素养校本化实施的培育研究 主持人 徐彬 工作单位 南通市海门证大中学 核心组成员 (包括主持人) 姓名 研究任务完成情况 (获得的主要成果、…...

大数据专业应该怎么学习

大数据学习不能停留在理论的层面上,大数据方向切入应是全方位的,基础语言的学习只是很小的一个方面,编程落实到最后到编程思想。学习前一定要对大数据有一个整体的认识。 大数据是数据量多吗?其实并不是,通过Hadoop其…...

学习黑客十余年,如何成为一名高级的安全工程师?

1. 前言 说实话,一直到现在,我都认为绝大多数看我这篇文章的读者最后终究会放弃,原因很简单,自学终究是一种适合于极少数人的学习方法,而且非常非常慢,在这个过程中的变数过大,稍有不慎&#…...

【算法】手把手学会二分查找

目录 简介 基本步骤 第一种二分 第二种二分 例题 搜索插入位置 数的范围 总结 简介 🥥二分查找,又叫折半查找,通过找到数据二段性每次都能将原来的数据筛选掉一半,通过这个算法我们能够将一个一个查找的 O(n) 的时间复杂…...

SVO、vinsmono、 OKVIS系统比较

几个经典视觉slam系统的比较 SVO 高翔链接:https://www.zhihu.com/question/39904950/answer/138644975处理的各个线程: tracking部分-frame to frame 、frame to map 金字塔的处理。这一步估计是从金字塔的顶层开始,把上一层的结果作为下一层估计的初…...

前端开发规范

一、开发工具 开发工具统一使用 VSCode代码格式化插件使用 Prettier代码格式校验使用 ESLintVSCode 需安装的插件有:ESLint、Prettier、Vetur 二、命名规范 项目命名使用小写字母,以连字符分隔 正确:fe-project 错误:FE PROJECT…...

不用科学上网,免费的GPT-4 IDE工具Cursor保姆级使用教程

大家好,我是可乐。 过去的一周,真是疯狂的一周。 GPT-4 震撼发布,拥有了多模态能力,不仅能和GPT3一样进行文字对话,还能读懂图片; 然后斯坦福大学发布 Alpaca 7 B,性能匹敌 GPT-3.5&#xff…...

【艾特淘】抖音小店物流体验分提升的6个维度,新手做店必看

抖音小店体验分,考核的内容包括商品、物流以及服务。大部分人会把重心放在商品评价和服务上,忽略了物流体验。但其实,抖音小店物流体验占比有20%,比服务分的占比还高一点。如果你的订单物流出了问题,很有可能会导致用户…...

数据结构——二叉树与堆

作者:几冬雪来 时间: 内容:二叉树与堆内容讲解 目录 前言: 1.完全二叉树的存储: 2.堆的实现: 1.创建文件: 2.定义结构体: 3.初始化结构体: 4.扩容空间与扩容…...

Three.js——learn02

Three.js——learn02Three.js——learn02通过轨道控制器查看物体OrbitControls核心代码index2.htmlindex.cssindex2.jsresult添加辅助器1.坐标轴辅助器AxesHelper核心代码完整代码2.箭头辅助器ArrowHelper核心代码完整代码3.相机视锥体辅助器CameraHelper核心代码完整代码Three…...

零基础小白如何入门网络安全?

我经常会看到这一类的问题: 学习XXX知识没效果; 学习XXX技能没方向; 学习XXX没办法入门; 给大家一个忠告,如果你完全没有基础的话,前期最好不要盲目去找资料学习,因为大部分人把资料收集好之…...

【前缀和】

前缀和前缀和子矩阵的和结语前缀和 输入一个长度为 n的整数序列。 接下来再输入 m 个询问,每个询问输入一对 l,r 对于每个询问,输出原序列中从第 l 个数到第 r个数的和。 输入格式第一行包含两个整数 n和 m 第二行包含 n个整数,表示整数…...

ChatGPT可以做WebRTC音视频质量性能优化,惊艳到我了

摘要 随着GPT-4的发布,AI的风越吹越旺。GPT-4可以回答问题,可以写作,甚至可以基于一张草图生成html代码搭建一个网站。即构社区的一位开发者倪同学就基于目前在研究的WebRTC QOS技术点对GPT-3.5跟GPT-4进行一场实验,ChatGPT会取代…...

MySQL数据库实现主从同步

安装MySQL数据库8.0.32 前言 今天来学习数据库主从同步的原理及过程,数据库主要是用来存储WEB数据,在企业当中是极为重要的,下面一起来看下。 1.1 数据库做主从的目的 MySQL主从复制在中小企业,大型企业中广泛使用&#xff0c…...

go语言gin框架学习

让框架去做http解包封包等,让我们的精力用在应用层开发 MVC模式 M: model,操作数据库gorm view 视图 处理模板页面 contoller 控制器 路由 逻辑函数 解决gin相关代码飘红的问题 记得启用gomodule go env -w GO111MODULEon然后到相应目录下执行 go mod i…...

Java奠基】Java经典案例讲解

目录 卖飞机票 找质数 开发验证码 数组元素的复制 评委打分 数字加密 数字解密 抢红包 模拟双色球 二维数组 卖飞机票 需求:机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。按照如下规则计算机票价格: 旺季&…...

新闻文本分类任务:使用Transformer实现

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...

如何在 Vue 中使用 防抖 和 节流

大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库 https://mp.weixin.qq.com/s?__bizMzU5NzA0NzQyNg&mid2247485824&idx3&sn70cd26a7c0c683de64802f6cb9835003&scene21#wech…...

美国Linux服务器系统增强安全的配置

美国Linux服务器系统可能出现的安全漏洞中,更多是由于不当的系统配置所造成的,用户们可以通过一些适当的安全配置来防止问题的发生。美国Linux服务器系统上运行的服务越多,不当配置的概率也就越高,那么系统出现安全问题的可能性也…...

【史上最全面esp32教程】oled显示篇

文章目录前言介绍及库下载基础使用引脚的连接使用函数总结前言 本节课主要讲的是OLED的基础使用。使用的oled为0.96寸,128*64。 大家的其他型号也是可以用的。 提示:以下是本篇文章正文内容,下面案例可供参考 介绍及库下载 oled的简介&…...

第十四届蓝桥杯三月真题刷题训练——第 21 天

目录 第 1 题:灭鼠先锋 问题描述 运行限制 代码: 思路: 第 2 题:小蓝与钥匙 问题描述 答案提交 运行限制 代码: 思路 : 第 3 题:李白打酒加强版 第 4 题:机房 第 1 题&#xff1…...

css绘制一个Pinia小菠萝

效果如下: pinia小菠萝分为头部和身体,头部三片叶子,菠萝为身体 头部 先绘制头部的盒子,将三片叶子至于头部盒子中 先绘制中间的叶子,利用border-radius实现叶子的效果,可以借助工具来快速实现圆角的预想…...

OpenCV入门(二十)快速学会OpenCV 19 对象测量

OpenCV入门(二十)快速学会OpenCV 19 对象测量1.对象测量2.多边形拟合3.计算对象中心作者:Xiou 1.对象测量 opencv 中对象测量包括: 如面积,周长,质心,边界框等。 弧长与面积测量; …...

TCP和UDP协议的区别?

是否面向连接: TCP 是面向连接的传输,UDP 是面向无连接的传输。 是否是可靠传输:TCP是可靠的传输服务,在传递数据之前,会有三次握手来建立连接;在数据传递时,有确认、窗口、重传、拥塞控制机制…...

【C语言蓝桥杯每日一题】——排序

【C语言蓝桥杯每日一题】—— 排序😎前言🙌排序🙌总结撒花💞😎博客昵称:博客小梦 😊最喜欢的座右铭:全神贯注的上吧!!! 😊作者简介&am…...

学校官网的制作

学校官网 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;}.top{background-color: #3D3BB8;width: 100%;position: fixed;padding: 20px 0 12px 0;}.box{width…...

【云原生】k8s集群命令行工具kubectl之故障排除和调试命令

kubectl之故障排除和调试命令一、describe二、logs三、attach四、exec五、port-forward六、proxy七、cp八、debug8.1、案例1&#xff1a;共享进程空间8.2、案例2&#xff1a;更改启动命令、容器镜像8.3、案例3&#xff1a;调试节点8.4、其他一、describe 显示某个资源或某组资…...

wordpress优缺点/网络营销方案ppt

容斥原理 设\(S_1,S_2,...,S_n\)为\(n\)个有限集合&#xff0c;\(|S|\)代表集合\(S\)的大小&#xff0c;则有 \[\left | \bigcup_{i1}^nS_i \right |\sum_{i1}^n|S_i|-\sum_{1\leq i \leq j \leq n}|S_i\cap S_j|...(-1)^{n1}\left | \bigcap_{i1}^nS_i \right |\] 多重集组合数…...

wordpress怎么添加网盘下载/seo站长博客

1. 获取镜像可以利用已有的FastDFS Docker镜像来运行FastDFS。获取镜像可以通过下载docker image pull delron/fastdfs也可是直接使用提供给大家的镜像备份文件文件下载地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1tB0Pk9NAeeyuKXOSkgVuwQ提取码&#xff1a;ry1…...

网站后台如何上传附件/新网站应该怎么做seo

大家好&#xff0c;我是本期的实验室研究员——李卫涵。今天我将向大家介绍如何基于针对 Source Generator 来进行单元测试。接下来就让我们一起到实验室中一探究竟吧&#xff01; Source Generator 单元测试 Intro Source Generator 是 .NET 5.0 以后引入的一个在编译期间动态…...

wordpress自动翻译插件/西安seo站内优化

新淘宝短视频就要计入手淘主搜&#xff0c;淘宝一直在变化&#xff0c;但是不变的是内容影响&#xff0c;做好内容&#xff0c;才能拥有明天的流量。做店铺&#xff0c;需要新方法&#xff0c;需要持续的去操作。 微淘作为卖家引流&#xff0c;以及提升粉丝活跃度粘性的工具&a…...

雅江网站建设/免费b站推广网站入口

上一节&#xff0c;我们将Models加入了实体对象模型&#xff08;Entity Frmaework模型&#xff09;接下来我们要完成控制层的代码编写&#xff1a; 1.在Controllers&#xff08;控制器&#xff09;目录点右建&#xff0c;添加一个控制器&#xff1a; 2.添加Home控制器: 3.添加A…...

学做网站用什么服务器/温州seo团队

1.下载链接Navicat for mysql客户端链接: https://pan.baidu.com/s/1dGbzgbR 密码: i43g2.安装mysql和NavicatNavicat for mysql,下载下来的本身就是个app,不用再次安装,直接拖拽到应用程序即可安装mysql,按照安装步骤安装即可,安装时会出现如下弹框,一定要记住,5.7之后的版本默…...