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"); // 添加元素
}
相关推荐
csbysj20205 分钟前
PHP 函数
开发语言
爬山算法12 分钟前
Netty(17)Netty如何处理大量的并发连接?
java·后端
spencer_tseng23 分钟前
springcloud + javaframework + h5
java·spring·spring cloud
_w_z_j_26 分钟前
Linux----线程互斥与同步
linux·运维·开发语言
云栖梦泽28 分钟前
易语言网络编程基础:构建网络版应用
开发语言
月明长歌1 小时前
【码道初阶】【Leetcode606】二叉树转字符串:前序遍历 + 括号精简规则,一次递归搞定
java·数据结构·算法·leetcode·二叉树
原来是好奇心1 小时前
深入Spring Boot源码(八):高级特性与扩展点深度解析
java·源码·springboot
oioihoii1 小时前
C++共享内存小白入门指南
java·c++·算法
布茹 ei ai1 小时前
QtWeatherApp - 简单天气预报软件(C++ Qt6)(附源码)
开发语言·c++·qt·开源·开源项目·天气预报