Java:LinkedList的使用

目录

一、概念

二、常用操作

[2.1 基于List的操作](#2.1 基于List的操作)

[2.2 队列(Queue)、栈(Stack)和双端队列(Deque)操作](#2.2 队列(Queue)、栈(Stack)和双端队列(Deque)操作)

[2.3 遍历](#2.3 遍历)


一、概念

LinkedList 在 Java 中是一个基于双向链表 实现的 List 接口的实现类。它同时实现了 ListDeque(双端队列)接口,所以它同时具备了列表和队列的特性。

核心特点:

  • 非连续存储:元素分散存储在堆内存中,通过引用相连。这使其在内存利用上更灵活,但每个元素需要额外的空间来存储前后节点的引用(内存开销更大)。

  • 动态大小:与数组不同,链表的大小是动态的,可以自由地添加和删除元素,无需担心容量问题。

  • 插入和删除高效在已知位置(通过迭代器定位)进行插入和删除操作的时间复杂度是 O(1) 。这是它相对于 ArrayList 最大的优势。因为它只需要修改相邻节点的引用即可,而不需要像数组那样移动大量元素。

  • 随机访问低效根据索引访问元素(get(i), set(i, element))的时间复杂度是 O(n)。因为它必须从链表的头部(或尾部,JDK 做了优化)开始遍历,直到找到第 i 个节点。

  • 实现了双端队列(Deque) :提供了丰富的方法,如 addFirst(), addLast(), removeFirst(), removeLast(), getFirst(), getLast() 等,可以非常方便地将其用作栈(Stack)、队列(Queue)或双端队列(Deque)。

二、常用操作

2.1 基于List的操作

java 复制代码
LinkedList<String> list = new LinkedList<>();

// 添加元素
list.add("Apple");        // 添加到尾部
list.add(1, "Banana");   // 在指定索引位置插入
list.addFirst("First");   // 添加到头部 (Deque 方法)
list.addLast("Last");     // 添加到尾部 (Deque 方法,等同于 add())

// 获取元素
String first = list.get(0);     // 根据索引获取
String head = list.getFirst();  // 获取头部元素
String tail = list.getLast();   // 获取尾部元素

// 删除元素
list.remove(1);           // 根据索引删除
list.remove("Apple");     // 根据元素内容删除(首次出现)
list.removeFirst();       // 删除并返回头部元素
list.removeLast();        // 删除并返回尾部元素

// 检查大小和内容
int size = list.size();
boolean isEmpty = list.isEmpty();
boolean hasApple = list.contains("Apple");

// 替换元素
list.set(0, "New First"); // 将索引0位置的元素替换

2.2 队列(Queue)、栈(Stack)和双端队列(Deque)操作

java 复制代码
LinkedList<String> queue = new LinkedList<>();

// 作为普通队列 (FIFO: First-In-First-Out)
queue.offer("A"); // 入队(添加到尾部),推荐使用
queue.add("B");   // 入队(添加到尾部),失败会抛异常
String s1 = queue.poll(); // 出队(移除并返回头部元素),队列空则返回null
String s2 = queue.remove(); // 出队,队列空则抛异常 NoSuchElementException
String s3 = queue.peek(); // 获取但不移除头部元素,空则返回null
String s4 = queue.element(); // 获取但不移除头部元素,空则抛异常

// 作为栈 (LIFO: Last-In-First-Out)
LinkedList<String> stack = new LinkedList<>();
stack.push("A"); // 压栈(添加到头部)
stack.push("B");
String top = stack.pop(); // 出栈(移除并返回头部元素)
String top2 = stack.peek(); // 查看栈顶元素

// 作为双端队列 (Deque)
queue.offerFirst("A"); // 添加到头部
queue.offerLast("Z");  // 添加到尾部(等同于 offer)
String first = queue.pollFirst(); // 从头部移除
String last = queue.pollLast();   // 从尾部移除

典型使用场景:

  • 实现栈(LIFO)addFirst() / removeFirst()

  • 实现队列(FIFO)offer() / poll()addLast() / removeFirst()

  • 实现双端队列 :各种 First/Last 方法

操作 方法示例 时间复杂度 说明
头部插入 addFirst(e), offerFirst(e) O(1)
尾部插入 add(e), addLast(e), offer(e), offerLast(e) O(1)
指定位置插入 add(index, e) O(n) 主要耗时在遍历到 index 位置
头部删除 removeFirst(), pollFirst() O(1)
尾部删除 removeLast(), pollLast() O(1)
指定元素/位置删除 remove(o), remove(index) O(n) 主要耗时在遍历找到元素或位置
随机访问(获取) get(index) O(n) 需要遍历
随机访问(修改) set(index, e) O(n) 需要遍历到位置后再修改,修改本身是 O(1)
查找元素位置 indexOf(o) O(n) 需要遍历比较
检查是否包含 contains(o) O(n) 内部调用 indexOf

队列使用示例:

java 复制代码
import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();

        // 生产者:入队10个任务
        for (int i = 0; i < 10; i++) {
            queue.offer(i);
            System.out.println("任务入队: " + i);
        }

        // 消费者:处理所有任务
        while (!queue.isEmpty()) {
            Integer task = queue.poll();
            System.out.println("处理任务: " + task);
        }
    }
}

2.3 遍历

千万不要用 for-i 循环(基于索引的循环)来遍历 LinkedList

因为每次 get(i) 都会从链表头开始遍历,会导致时间复杂度变为 O(n²),性能极差。

java 复制代码
// foreach 循环(推荐):语法简洁,底层使用迭代器,效率高。
for (String item : list) {
    System.out.println(item);
}


// 迭代器(Iterator):更灵活,可以在遍历时使用 iterator.remove() 安全地删除元素。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if ("某些条件") {
        iterator.remove(); // 安全删除!
    }
}


// ListIterator:功能更强大的迭代器,可以双向遍历(向前/向后)以及在遍历时添加和修改元素。
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    String next = listIterator.next();
    listIterator.set("Modified: " + next); // 修改元素
    listIterator.add("Added"); // 添加元素
}
相关推荐
欢迎来到祖安!16 小时前
企业微信 API 接口能力介绍:支持消息收发、图片发送、表情互动、联系人管理等多场景应用
java·前端·数据仓库·spring cloud·企业微信
dadaobusi20 小时前
学习:RV lkvm SBI
java·学习·spring
djarmy21 小时前
MAIN.c(1): warning C318: can’t open file ‘STC8G.H’ 报错 解决 分析
c语言·开发语言·mongodb
HEJOO91 天前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧1 天前
Java:no content to map due to end of input
java·开发语言
阿维的博客日记1 天前
Example 类全场景实战指南
java·mybatis
梦梦代码精1 天前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
两点王爷1 天前
SpringBoot 项目集成 GeoServer 源码,实现地图服务发布
java·spring boot·后端
隔窗听雨眠1 天前
记一次SQL Server数据库性能分析:从CPU100%到单配置修复的完整诊断
开发语言·数据库·php
David猪大卫1 天前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试