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

LinkedList的模拟实现+LinkedList和ArrayList的区别

目录

LinkedList的模拟实现

什么是双向链表

增加数据

头插法:

 尾插法:

指定的下标插入:

删除数据

 删除双向链表中出现的第一个key

置空所有数据

LinkedList和ArrayList的区别


        

顺序表对应的集合类是ArrayList;链表对应的集合类是LinkedList,在Java集合框架中,它们是两种最基础也是最常用的数据结构实现,它们的底层实现原理和性能差异是怎么样的呢?这里我们先来模拟实现LinkedList;

LinkedList的模拟实现

什么是双向链表

        首先,我们要知道的是LinkedList的底层使用了双向链表,那么什么是双链表呢?我们前面学过单链表是由一个个节点组成,节点中包括数据域和指针域的一个链表其中指针域存放着下一个节点的地址值:

        双向链表同样也是由一个个节点组成,多了个prev指针,指向前驱节点的地址,和一个last指针指向最后一个节点;那么我们如何构建一个双向链表呢?基于单链表的学习,双向链表我们模仿单链表的样式去写就简单很多了:

    //1.想构成链表的是?->节点由什么组成?定义变量 一个节点为一个对象定义成内部类static class ListNode{public int val;public ListNode next;public ListNode prev;//构造一个节点,只需要实例化public ListNode(int val) {this.val = val;}}//指向节点的一些指针public ListNode head;public ListNode last;//始终指向最后一个节点

         这样写好一个链表的基本结构我们就可以为这个链表写一些操作方法了;双向链表有一些操作时不太涉及prev指针域的,这些操作是跟前面学习的单链表一致的,比如:链表打印display、表长size、查找链表的元素contains、这里就不重复记录了;具体看单链表的手动实现+相关习题,这里主要介绍与单链表有点区别的操作。

增加数据

头插法:

    public void addFirst(int data) {//1.实例化一个节点ListNode node = new ListNode(data);//2.链表尾空if (head == null){head = node;last = node;}else {node.next = head;//先绑定后面head.prev = node;head = node;}return;}

双向链表中有两个指针域,操作节点是要尤其注意操作指针域的顺序,要避免数据丢失的情况。 

 尾插法:

    public void addLast(int data) {ListNode node = new ListNode(data);if (head == null){head = node;last = node;}else {last.next = node;node.prev = last;last = node;//注意要更新last节点,保证last是最后一个节点}}

指定的下标插入:

        在指定下标位置进行插入时,我们重点要关注的是中间插入元素是的操作顺序

    public void addIndex(int index, int data) {ListNode node = new ListNode(data);//1.判断index合法性if (index < 0 && index > size()){throw new IndexException("index非法" + index);}//2.index为0时,头插if (index == 0){addFirst(data);return;}//index为size时,尾插if (index == size()){addLast(data);return;}//3.找indexListNode cur = findIndex(index);//注意顺序node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}private ListNode findIndex(int index){ListNode cur = head;int count = 0;while (count != index){//因为是双向链表,可以访问到节点的前驱和后继,所以不用跟单链表一样找index-1cur = cur.next;count++;}return cur;}

删除数据

 删除双向链表中出现的第一个key

注意:删除时要考虑到所有特殊的情况,比如删除头结点、尾结点、链表只有一个节点的情况:

    public void remove(int key) {//遍历找keyListNode cur = head;while (cur != null){if (cur.val == key ){//1.要删的节点是头结点if (cur == head){head = head.next;if (head != null){head.prev = null;}else {//链表只有一个节点且是需要删除的节点,也得置空last = null;}return;}else {if (cur.next == null){//删除尾结点cur.prev.next = null;last = last.prev;}else {//删除中间节点cur.prev.next = cur.next;cur.next.prev = cur.prev;}}return;}cur = cur.next;}}

        删除第一个key值得代码我们写出来了,那么删除所有key值也非常得简单了,把return去掉让他继续往下遍历往下删除即可;

置空所有数据

        我们可以直接简单粗暴的分别把head和last置空,导致整个表置空;也可以把每个节点的指针域依次置空 ,本质上两种方法时一样的:

    public void clear() {//循环把节点依次置空ListNode cur = head;while (cur != null){//定义一个指针指向即将被删除的节点,记录下下一个要被删除的节点ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}this.head = null;this.last = null;}

LinkedList和ArrayList的区别

存储空间方面:

  • ArrayList物理存储和逻辑顺序都是连续的(基于动态数组实现)。

  • LinkedList逻辑上是连续的,但物理存储不一定连续(基于双向链表实现)。

查找修改效率:

  • ArrayList是数组结构,支持随机访问,可以直接通过索引定位元素,效率极高O(1);修改的第一步也是要访问,所以修改的时间复杂度也为O(1)

  • LinkedList不支持随机存取,必须从头或尾遍历链表,访问效率较低O(n)

插入和删除元素效率:

  • ArrayList 插入或删除除了头节点和尾结点元素时,需要移动后续所有元素,效率较低O(n)

  • LinkedList只需调整相邻节点的指针,无需移动数据,效率更高O(1)

扩容机制:

  • ArrayList:采用静态分配,初始容量固定,扩容时需要重新分配更大的数组并复制数据,时间复杂度 O(n)。可能导致空间浪费或频繁扩容。

  • LinkedList:动态分配,每次插入新元素时才分配内存,无需扩容。没有容量限制,但每个节点需要额外存储指针,占用更多内存。

适用场景:

  • ArrayList:适合读多写少的场景,。

  • LinkedList:适合增删频繁的场景。


 感谢大家阅读📚点赞👍收藏⭐评论✍关注❤

博客主页: 【长毛女士-CSDN博客 

http://www.lryc.cn/news/597612.html

相关文章:

  • 低代码中的统计模型是什么?有什么作用?
  • 海外短剧系统全栈开发指南:从视频编解码到全球CDN架构实战
  • 什么是5G-A三防平板?有什么特点?哪些领域能用到?
  • SpringBoot 内嵌 Tomcat 的相关配置
  • 上网行为管理之身份认证实验
  • 纯CPU场景下C++的分布式模型训练框架设计思路
  • 18.设备虚拟化
  • LeetCode 407:接雨水 II
  • SQL 中 CASE WHEN 及 SELECT CASE WHEN 的用法
  • SparkSQL 聚合函数 MAX 对 NULL 值的处理
  • 基于多种机器学习的水质污染及安全预测分析系统的设计与实现【随机森林、XGBoost、LightGBM、SMOTE、贝叶斯优化】
  • 小白做投资测算,如何快速上手?
  • 网安-SQL注入-sqli-labs
  • OpenLayers 快速入门(七)矢量数据
  • Centos7.9多网卡绑定做链路聚合
  • 回顾 Palantir:八年之旅的反思
  • 《P4092 [HEOI2016/TJOI2016] 树》
  • 线段树学习笔记 - 练习题(1)
  • UniApp X 网络请求避坑指南:从 JS 到 UTS 的 JSON 数据处理全解析
  • Neo4j 框架 初步简单使用(基础增删改查)
  • OpenEuler系统架构下编译redis的RPM包
  • 【基于OpenCV的图像处理】图像预处理之图像色彩空间转换以及图像灰度化处理
  • 【web页面接入Apple/google/facebook三方登录】
  • SQL基础⑥ | 聚合函数
  • Java项目中定时任务三方工具和技术的深度应用指南
  • Kubernetes 日志收集
  • biji 1
  • 事务与索引:数据库核心机制详解
  • 解析云蝠智能 VoiceAgent 的技术架构与应用实践
  • Linux第三天Linux基础命令(二)