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"); // 添加元素
}
相关推荐
明月看潮生1 小时前
编程与数学 02-017 Python 面向对象编程 23课题、测试面向对象的程序
开发语言·python·青少年编程·面向对象·编程与数学
2401_831501731 小时前
Linux之Docker虚拟化技术(一)
java·linux·docker
TPBoreas1 小时前
架构设计模式七大原则
java·开发语言
自由的疯1 小时前
Java 实现TXT文件导入功能
java·后端·架构
开开心心就好1 小时前
PDF转长图工具,一键多页转图片
java·服务器·前端·数据库·人工智能·pdf·推荐算法
现在没有牛仔了1 小时前
SpringBoot实现操作日志记录完整指南
java·spring boot·后端
小蒜学长1 小时前
基于django的梧桐山水智慧旅游平台设计与开发(代码+数据库+LW)
java·spring boot·后端·python·django·旅游
浮游本尊1 小时前
Java学习第16天 - 分布式事务与数据一致性
java
浮游本尊2 小时前
Java学习第15天 - 服务网关与API管理
java
nightunderblackcat2 小时前
新手向:Python开发简易股票价格追踪器
开发语言·python