【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)

目录

  • 一、双向链表
  • 二、node(int index) 根据索引找节点
  • 三、clear()
  • 四、add(int, E)
  • 五、remove(int index)
  • 六、双向链表和单链表
  • 七、双向链表和动态数组
  • 八、jdk 官方的 LinkedList 的 clear() 方法

一、双向链表

在这里插入图片描述

🎁 单链表的节点中只有一个 next 指针引用着下一个节点的地址
🎁 当要获取单链表中的最后一个元素的时候,需要从头节点开始遍历到最后
🎁 单链表一开始的时候有 first 头指针引用着头节点的地址

💰 双向链表可以提升链表的综合性能
💰 双向链表的节点中有 prev 指针引用着一个节点的地址,有 next 指针引用着一个节点的地址
💰 双向链表中一开始的时候有 first 头指针引用着头节点的地址,有 last 尾指针引用着尾节点的地址
💰 ① 当需要获取双向链表靠后的节点【index >= (size / 2)】的时候从尾节点开始遍历;② 当需要获取双向链表靠前的节点【index < (size / 2)】的时候从头节点开始遍历

🎄 头节点的 prev 为 null
🎄 尾节点的 next 为 null

二、node(int index) 根据索引找节点

  /*** 根据索引找节点*/private Node<E> node(int index) {rangeCheck(index);if (index < (index >> 1)) { // 找左边的节点Node<E> node = first;for (int i = 0; i < index; i++) {node = node.next;}return node;} else {Node<E> node = last;for (int i = size - 1; i > index; i--) {node = node.prev;}return node;}}

三、clear()

  @Overridepublic void clear() {size = 0;first = null;last = null;}

只有被【gc root 对象】引用的对象才不会被垃圾回收器回收:

🍃 被栈指针(局部变量)引用的对象是 gc root 对象

在这里插入图片描述

在这里插入图片描述

四、add(int, E)

在这里插入图片描述

🎄 ① 当往索引 0 处插入节点的时候
🎄 ② 当往最后插入节点的时候
🎄 ③ 当一个节点都没有(插入第一个节点)的时候

在这里插入图片描述

在这里插入图片描述

    @Overridepublic void add(int index, E element) {rangeCheck4Add(index);if (size == 0 || (first == null && last == null)) { // 添加第一个节点// 新节点的 prev 和 next 都指向 nullfirst = new Node<>(element, null, null);// 头指针和尾指针都指向新节点last = first;} else {if (index == size) { // 往最后插入新节点Node<E> oldLast = last;last = new Node<>(element, oldLast, null);oldLast.next = last;} else {// 找到 index 索引处的节点(该节点是新节点的下一个节点)Node<E> next = node(index);// 前一个节点(假如是往索引为 0 的位置插入节点的话, prev 是 null)Node<E> prev = next.prev;// 新节点的 prev 指向【前一个节点】// 新节点的 next 指向【后一个节点】Node<E> newNode = new Node<>(element, prev, next);// 后一个节点的 prev 指向新节点next.prev = newNode;/* 往索引为 0 处插入新节点 */if (prev == null) { // 往索引为 0 的位置插入新节点(插入新节点到头节点的位置)first = newNode; // 头指针指向新节点} else {// 前一个节点的 next 指向新节点prev.next = newNode;}}}size++;}

在这里插入图片描述

五、remove(int index)

在这里插入图片描述

自己写的代码(测试成功的):

    @Overridepublic E remove(int index) {rangeCheck(index);// 拿到 index 位置的节点Node<E> oldNode = node(index);if (index == 0) { // 删除头节点// 拿到头节点first = oldNode.next;first.prev = null;} else {oldNode.prev.next = oldNode.next;if (oldNode.next == null) { // 删除尾节点last = oldNode.prev;} else {oldNode.next.prev = oldNode.prev;}}size--;return oldNode.element;}

老师的代码:

    @Overridepublic E remove(int index) {rangeCheck(index);Node<E> node = node(index);Node<E> prev = node.prev;Node<E> next = node.next;if (prev == null) { // 删除头节点first = next;} else {prev.next = next;}if (next == null) { // 删除尾节点last = prev;} else {next.prev = prev;}size--;return node.element;}

在这里插入图片描述

六、双向链表和单链表

在这里插入图片描述

🎉 双向链表相比单向链表操作数量缩减一半

七、双向链表和动态数组

🌱 动态数组:开辟、销毁内存空间的次数相对较少但可能造成内存空间浪费(可以通过缩容解决)
🌱 双向链表:开辟、销毁内存空间的次数相对较多(每次添加元素都会创建新的内存空间 ),但不会造成内存空间的浪费

🌿 如果需要频繁在尾部进行添加删除操作,动态数组双向链表 均可选择

  • 动态数组在尾部添加和删除都是 O(1) 级别的
  • 双向链表由于有尾指针 last 的存在,在尾部添加和删除的操作也是 O(1) 级别的

🌿 如果需要频繁在头部进行添加删除操作,建议选择使用 双向链表

  • 动态数组头部的添加和删除操作需要进行大量的元素挪动
  • 双向链表有头指针 first 的存在,在头部进行添加删除操作效率很高

🌿 如果需要频繁地(在任意位置)进行添加删除操作,建议选择使用双向链表

  • 动态数组有最坏情况(假如是在头部添加或删除几乎需要挪动全部元素)
  • 双向链表最多就遍历 n/2 次(n 是元素数量)

🌿 如果有频繁的查询操作(随机访问操作),建议选择使用动态数组

  • 动态数组的随机访问是 O(1) 级别的,通过下标 index 可以直接定位到元素的内存地址
  • 双向链表每次查询都需要遍历,最坏情况要遍历 size 次(size 是元素个数)

❓ 相比单链表,双向链表效率很高。哪有了双向链表,单向链表是否就没有任何用处了呢 ❓
🌿 哈希表的设计中就用到了单链表 😀

八、jdk 官方的 LinkedList 的 clear() 方法

在这里插入图片描述

  • 我学习数据结构与算法的全部代码:https://gitee.com/zgq666good/datastructureandalgorithm.git
  • 学习资料来自于我偶像 ~ 李明杰(小码哥教育)
    在这里插入图片描述

🌿如有错误,请不吝赐教🌿

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

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

相关文章

STM32面试知识点总结分析

一、STM32F1和F4的区别&#xff1f; 内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b; 主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b; 浮点运算&#xff1a;F1无浮点运算单位&#xff0c;F4有&#xff1b; 功能性…

高压线路零序电流方向保护程序逻辑原理(四)

2&#xff0e;全相循环程序逻辑框图 全相循环程序逻辑简图如图3&#xff0d;18所示。程序入口首先检测标志位UQDB1&#xff0c;在采样中断服务程序中采用3U。突变量来区分接地故障和TA断线&#xff0c;接地故障时Δ3U。大于定值&#xff0c;置标志位UQDB1&#xff0c;这是11型…

Elasticsearch 安装

下载安装 elasticsearch下载链接 运行&#xff1a;bin\elasticsearch.bat 设置密码&#xff1a;.\bin\elasticsearch-setup-passwords interactive 这边设置密码遇到一个坑 PS G:\elasticsearch-8.8.1> .\bin\elasticsearch-setup-passwords interactiveFailed to authe…

AI实战营第二期 第七节 《语义分割与MMSegmentation》——笔记8

文章目录 摘要主要特性 案例什么是语义分割应用&#xff1a;无人驾驶汽车应用&#xff1a;人像分割应用&#xff1a;智能遥感应用 : 医疗影像分析 三种分割的区别语义分割的基本思路按颜色分割逐像素份分类全卷积网络 Fully Convolutional Network 2015存在问题 基于多层级特征…

Python 基于招聘数据可视化系统

1 简介 Python 基于招聘数据可视化系统&#xff0c;视频效果如下&#xff1a; 基于Python的招聘信息可视化系统&#xff0c;附源码 随着国内的经济不断的快速发展&#xff0c;现在学生的就业压力也在逐年增加&#xff0c;网络上的招聘信息非常的丰富&#xff0c;但是对于学生而…

高等数学下拾遗+与matlab结合

如何学好高等数学 高等数学是数学的一门重要分支&#xff0c;包括微积分、线性代数、常微分方程等内容&#xff0c;它是许多理工科专业的基础课程。以下是一些学好高等数学的建议&#xff1a; 扎实的基础知识&#xff1a;高等数学的内容很多&#xff0c;包括初等数学的一些基…

回归预测 | MATLAB实现PSO-CNN粒子群算法优化卷积神经网络的数据多输入单输出回归预测

回归预测 | MATLAB实现PSO-CNN粒子群算法优化卷积神经网络的数据多输入单输出回归预测 目录 回归预测 | MATLAB实现PSO-CNN粒子群算法优化卷积神经网络的数据多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 回归预测 | MATLAB实现PSO-CNN粒子群算法优…

通过Jenkins实现Unity多平台自动打包以及相关问题解决

简介 通过本文可以了解到如何在windows和mac上部署Jenkins。并且通过Jenkins实现Unity在IOS,安卓和PC等多平台自动打包的功能&#xff0c;并且可以将打包结果通过飞书机器人同步到飞书群内。优化工作流&#xff0c;提高团队的开发效率。文末记录了实际使用Jenkins时遇到的各种问…

探索数字化前沿:数字化产品引领科技创新风潮

随着数字化时代的到来&#xff0c;国内数字化产品市场蓬勃发展&#xff0c;涌现出许多引领行业变革的产品。本文将介绍几个在数字孪生和人工智能领域取得突破的国内产品&#xff0c;带大家了解数字化产品的创新应用和影响力。 山海鲸可视化&#xff1a;山海鲸可视化是一款强大…

如何使用 Terraform 和 Git 分支有效管理多环境?

作者&#xff5c;Sumeet Ninawe 翻译&#xff5c;Seal软件 链接&#xff5c;https://spacelift.io/blog/terraform-environments 通常我们使用 Terraform 将我们的基础设施定义为代码&#xff0c;然后用 Terraform CLI 在我们选择的云平台中创建制定的基础设施组件。从表面上看…

Redis 6.2.4集群搭建

1. 说明 这里使用的是redis的cluster集权模式&#xff0c;没有用哨兵模式&#xff08;哨兵模式依赖哨兵节点&#xff0c;哨兵节点一旦挂掉就不再高可用了&#xff0c;因此没有采用&#xff09;。 由于Redis Cluster至少需要6个节点&#xff0c;因此&#xff0c;这里咱们采用的…

lesson7-1 Zigbee协议栈的使用

目录 协议栈的使用 协议栈的安装和协议栈工程创建 协议栈工程配置 选项卡选择 用户代码编写注意 信道选择及PANID分配 协议栈的使用 协议栈的安装和协议栈工程创建 首先进行协议栈的安装 如何创建自己的协议栈工程&#xff1a; &#xff08;1&#xff09;先把整个协议…