news 2026/4/23 13:13:35

数据结构(Java版)第八期:LinkedList与链表(三)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据结构(Java版)第八期:LinkedList与链表(三)

数据结构第八期:LinkedList 与链表(Java 版)

这是 Java 中最常被问到的数据结构之一,也是面试、笔试、日常开发中最容易踩坑的地方。

下面从原理 → 源码 → 常见操作 → 面试高频题 → 实际使用建议完整梳理一遍。

1. LinkedList 在 Java 中的真实身份

publicclassLinkedList<E>extendsAbstractSequentialList<E>implementsList<E>,Deque<E>,Cloneable,java.io.Serializable

一句话总结:
LinkedList 同时实现了 List 和 Deque 接口,所以它既是“双向链表”,也是“双端队列”

最关键的两点:

  • 底层是双向链表(doubly-linked list)
  • 没有像 ArrayList 那样的连续数组存储

2. 核心内部结构(JDK 8/11/17/21 一致)

privatestaticclassNode<E>{Eitem;// 元素本身Node<E>next;// 后继指针Node<E>prev;// 前驱指针}

三个重要成员变量:

transientintsize=0;// 元素个数transientNode<E>first;// 头节点(first)transientNode<E>last;// 尾节点(last)

最经典的图示(双向链表)

null ← prev [prev | item | next] ↔ [prev | item | next] ↔ [prev | item | next] next → null ↑ first ↑ last

3. 常用操作的时间复杂度(面试必背)

操作时间复杂度说明
get(index)O(n)从头/尾选近的一端开始遍历
set(index, element)O(n)同上,需要找到第 index 个节点
addFirst / addLastO(1)直接操作 first/last 指针
add(index, element)O(n)找到位置 + 修改指针(最坏 O(n))
removeFirst / removeLastO(1)直接操作 first/last
remove(Object o)O(n)需要线性查找 + 修改指针
remove(index)O(n)找到节点 + 修改前后指针
contains(Object o)O(n)线性查找
size() / isEmpty()O(1)直接返回 size 字段
iterator() / listIterator()O(1)返回链表迭代器(支持双向遍历)

一句话总结
凡是涉及“按索引操作”的几乎都是 O(n),凡是“头尾操作”的都是 O(1)

4.LinkedList 作为 Deque(双端队列)的常用方法

LinkedList 实现了 Deque 接口,所以可以用它当队列双端队列用。

场景首选方法(推荐)等价方法(不推荐抛异常版)说明
入队(尾)offerLast(e) / addLast(e)add(e)尾插
出队(头)pollFirst()removeFirst()头出,空返回 null
入栈(头)push(e)addFirst(e)头插(栈顶)
出栈(头)pop()removeFirst()头出(栈顶)
取头peekFirst()getFirst()看头元素,不删除
取尾peekLast()getLast()看尾元素,不删除

面试最爱问的写法对比

// 当栈用(LIFO)LinkedList<Integer>stack=newLinkedList<>();stack.push(1);// 入栈stack.push(2);stack.pop();// 出栈 → 2
// 当队列用(FIFO)LinkedList<Integer>queue=newLinkedList<>();queue.offer(1);// 入队queue.offer(2);queue.poll();// 出队 → 1

5. 源码中最容易被问到的几个点

  1. addFirst / addLast 的实现(O(1))
publicvoidaddFirst(Ee){linkFirst(e);}privatevoidlinkFirst(Ee){finalNode<E>f=first;finalNode<E>newNode=newNode<>(null,e,f);first=newNode;if(f==null)last=newNode;elsef.prev=newNode;size++;modCount++;}
  1. get(int index) 为何慢(O(n))
publicEget(intindex){checkElementIndex(index);returnnode(index).item;}Node<E>node(intindex){// assert isElementIndex(index);if(index<(size>>1)){// 前半段从头开始找Node<E>x=first;for(inti=0;i<index;i++)x=x.next;returnx;}else{// 后半段从尾开始找(关键优化!)Node<E>x=last;for(inti=size-1;i>index;i--)x=x.prev;returnx;}}
  1. 为什么 LinkedList 实现了 RandomAccess 接口?

答案它其实没有实现 RandomAccess
(ArrayList 实现了,LinkedList 没有)

publicclassArrayList<E>...implementsRandomAccess...publicclassLinkedList<E>...// 没有 implements RandomAccess

这也是为什么List遍历时推荐用for-eachiterator,而不是get(i)循环的原因。

6. 面试高频题 TOP 10(带答案)

  1. LinkedList 是线程安全的吗?
    否。所有方法都没有 synchronized。

  2. LinkedList 和 ArrayList 的区别?(必问)

项目ArrayListLinkedList
底层结构动态数组双向链表
随机访问O(1)O(n)
插入/删除(头尾)O(n)(需移动元素)O(1)
插入/删除(中间)O(n)O(n)(查找)+O(1)(修改指针)
内存开销较小(连续)较大(每个节点有 prev/next)
适用场景读多写少、频繁随机访问频繁头尾增删、队列/栈
  1. LinkedList 可以当栈和队列用吗?怎么用?
    可以。推荐用 push/pop 当栈,offer/poll 当队列。

  2. 为什么 LinkedList 没有 capacity(容量)概念?
    因为是链表,不需要预分配空间。

  3. Iterator 和 ListIterator 的区别?
    LinkedList 的 iterator() 是单向的,listIterator() 是双向的,支持 add/set/remove。

  4. modCount 有什么作用?
    快速失败机制(fail-fast)。结构修改时 modCount++,迭代器发现 modCount 变化就抛 ConcurrentModificationException。

  5. ConcurrentLinkedQueue 和 LinkedList 的区别?
    前者是线程安全的无界队列(CAS),后者非线程安全。

  6. 为什么不建议用 LinkedList 做大数据量的随机访问?
    每次 get(i) 都要从头/尾遍历,时间复杂度 O(n),n 很大时很慢。

  7. LinkedList 的 subList() 返回的是什么?
    SubList 内部类,是原链表的视图,修改会影响原链表(非深拷贝)。

  8. 实际项目中什么时候选 LinkedList?

7. 2026 年真实使用建议

需要我手写一个双向链表的完整实现(不依赖 LinkedList)吗?
或者想看 LinkedList 在 LeetCode 哪些题中是最佳解?
随时告诉我~

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 13:50:24

Z-Image-Turbo适合哪些场景?一文说清楚

Z-Image-Turbo适合哪些场景&#xff1f;一文说清楚 1. 为什么Z-Image-Turbo值得关注&#xff1f; 你有没有遇到过这样的情况&#xff1a;急着出一张电商主图&#xff0c;结果AI生成要等十几秒&#xff1b;想做个带中文标语的海报&#xff0c;生成的文字却是乱码&#xff1b;好…

作者头像 李华
网站建设 2026/4/18 9:13:29

Z-Image-Turbo避坑指南:这些启动细节千万别忽略

Z-Image-Turbo避坑指南&#xff1a;这些启动细节千万别忽略 你兴冲冲下载了Z-Image-Turbo镜像&#xff0c;docker run一气呵成&#xff0c;supervisorctl start z-image-turbo敲得行云流水&#xff0c;浏览器打开127.0.0.1:7860——结果页面空白、加载转圈、控制台报错404&…

作者头像 李华
网站建设 2026/3/25 11:02:29

DFS-字符串分割-数字字符串转化成IP地址

求解代码 ArrayList<String> ans new ArrayList<>();public ArrayList<String> restoreIpAddresses (String s) {if(snull||s.length()<4||s.length()>12){return ans;}StringBuilder sb new StringBuilder();dfs(s,sb,0,0);return ans;}private vo…

作者头像 李华
网站建设 2026/4/16 15:29:20

技术演进中的开发沉思-328 JVM:垃圾回收(上)

在 JVM 的内存管理中&#xff0c;“判定对象是否存活” 是 GC 的核心前提 —— 如果把 GC 比作 JVM 的 “垃圾清洁工”&#xff0c;那可达性分析算法就是 “清洁工的判定标准”&#xff0c;引用类型就是 “给对象贴的不同标签”&#xff1a;有的对象&#xff08;强引用&#xf…

作者头像 李华
网站建设 2026/3/31 8:12:11

YOLOv5主干网络替换实战:基于ShuffleNetV2的轻量化改进与性能优化教程

文末含资料链接和视频讲解! 文章目录 一、轻量化网络技术背景 1.1 移动端部署的挑战 1.2 ShuffleNet系列演进 二、ShuffleNetV2模块深度解析 2.1 通道混洗机制 2.2 Shuffle_Block结构 三、YOLOv5集成ShuffleNetV2全流程 3.1 代码修改实战 步骤1:common.py新增模块 步骤2:yo…

作者头像 李华