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

Java集合中的 LinkedList

本文主要是在单向不带头链表的基础上,探讨并实现的双向不带头链表 LinkedList。

一、认识 LinkedList

说明:

1、在集合框架中,LinkedList 也实现了List接口;

2、LinkedList 的底层使用了双向链表;

3、LinkedList 没有实现 RandomAccess 接口,因此 LinkedList 不支持随机访问;

4、LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)

5、LinkedList比较适合任意位置插入的场景。

        在具体实现 LinkedList 的方法前,我们需要注意,单向链表不能回退找前一个节点,但是双向链表可以通过 prev 引用找到前一个节点,因此定义的临时变量比单向链表少。

二、LinkedList 的模拟实现

        与单向链表的功能一致。其中 display()、size()、contains() 方法一模一样,而其他方法因为不用考虑前一个节点怎么获得的问题,因此需要重写画图思考如何实现。

重点是删除节点的方法:

public class MyLinkedList{static class ListNode{public int val;public ListNode prev;public ListNode next;public ListNode(int val){this.val = val;}}public ListNode head;public ListNode last;   // 标志最后一个节点public void display(){ListNode cur = head;while(cur != null){System.out.print(cur.val + " ");cur = cur.next;}System.out.println();}public int size(){int count = 0;ListNode cur = head;while(cur != null){count++;cur = cur.next;}return count;}public boolean contains(int key){ListNode cur = head;while(cur != null){if(cur.val == key){return true;}cur = cur.next;}return false;}public void addFist(int data){ListNode newNode = new ListNode(data);if(head == null){head = last = newNode;return;}head.prev = newNode;newNode.next = head;head = newNode;}public void addLast(int data){ListNode newNode = new ListNode(data);if(head == null){head = last = newNode;return;}last.next = newNode;newNode.prev = last;last = newNode;}public void addIndex(int index, int data) throws IllegalIndexException{  // 自己编写的异常处理int len = this.size();  // 两次使用size()时用变量进行存储可提高效率if(index < 0 || index > len){throw new IllegalIndexException("指定位置不合法!!!");}if(index == 0){addFist(data);return;}if(index == len){addLast(data);return;}ListNode newNode = new ListNode(data);ListNode cur = findIndex(index);newNode.next = cur;cur.prev.next = newNode;newNode.prev = cur.prev;cur.prev = newNode;}private ListNode findIndex(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}public void remove(int key) {ListNode cur = head;while (cur != null){if (cur.val == key){if (cur == head){  // 开头head = head.next;if (head != null){  // 考虑了只有一个节点就不进来head.prev = null;}}else{cur.prev.next = cur.next;  // 中间和结尾的删除if (cur.next == null){     // 尾节点的删除last = last.prev;}else{cur.next.prev = cur.prev;  // 中间节点的删除}}return;   // 删除完毕,循环结束}cur = cur.next;  // cur.val != key 就前进}}public void removeAllKey(int key) {ListNode cur = head;while (cur != null){if (cur.val == key){if (cur == head){head = head.next;if (head != null){head.prev = null;}}else{cur.prev.next = cur.next;if (cur.next == null){last = last.prev;}else{cur.next.prev = cur.prev;}}//return;   // 比remove少了该语句,}cur = cur.next;  // cur.val != key 就前进}}public void clear() {ListNode cur = head;while (cur != null){ListNode perNode = cur.next;cur.prev = null;cur.next = null;cur = perNode;}head = last = null;}
}

三、LinkedList 的方法

与 ArrayList 一致。此处不再赘述。

方法解释
size()获取有效元素个数
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素,该元素之后的元素统一往前搬移一个位
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list

四、ArrayList 顺序表 与 LinkedList 链表的不同

不同点ArrayListLinkedList
存储方式物理上一定连续,即逻辑上相邻的元素在内存中也相邻。逻辑相邻的元素物理位置不相邻
随机访问通过下标直接访问元素,时间复杂度为O(1)不支持随机访问,查询节点数据的时间复杂度为O(N)
插入/删除头部或中间插入/删除元素时,需移动其他元素,最坏情况下时间复杂度为O(N)只需要修改指针指向,操作时间复杂度为O(1)
扩容机制需预分配连续空间,扩容成本高且可能造成空间浪费按需分配空间,动态管理内存,无扩容成本
适用场景适用于数据量稳定、频繁随机访问的场景(如缓存数据)适用于频繁插入/删除操作且数据量不确定的场景(如动态列表)
空间利用率一次性申请大量空间,可能造成空间浪费按需分配,空间利用率更高
http://www.xdnf.cn/news/1276003.html

相关文章:

  • 每日任务day0810:小小勇者成长记之武器精炼
  • node.js 学习笔记3 HTTP
  • Django @login_required实现登陆认证
  • C/C++内存管理函数模板
  • 小明的魔法地图:迷宫探险智慧(记忆性递归)
  • 【0基础3ds Max】主工具栏介绍(下)
  • [激光原理与应用-223]:机械 - 机加厂加工机械需要2D还是3D图?
  • Python设计模式 - 装饰模式
  • 六、RuoYi-Cloud-Plus OSS文件上传配置
  • QT常用控件三
  • Qt—— 下载、工具介绍以及新建项目
  • 从0开始的中后台管理系统-5(userList页面功能实现)
  • 40.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--扩展功能--集成网关--初始化网关
  • Pytorch进阶-timm库-00快速开始
  • (三)全栈(部署)
  • 精准计算Word文档页数的PHP类
  • 数据结构-deque(双端队列)和queue(队列)区别
  • 【npm、yarn、pnpm】特点对比,按需选择
  • Java 后端性能优化实战:从 SQL 到 JVM 调优
  • 分布微服务电商订单系统Rust编码开发[上]
  • 数组练习(一)
  • vuhub drippingblues靶场攻略
  • #4:MinIO分片上传和集群部署
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DHCP欺骗、DHCP饿死)
  • 安全运维的核心
  • C语言——深入理解指针(二)
  • 【递归、搜索与回溯算法】递归算法
  • Ollama+Deepseek+Docker+RAGFlow打造自己的私人AI知识库
  • 计算机网络:超网即路由聚合一定需要连续的IP地址吗?
  • 秋招春招实习百度笔试百度管培生笔试题库百度非技术岗笔试|笔试解析和攻略|题库分享