Java 集合框架:LinkedList 的介绍、使用、原理与源码解析

大家好,我是栗筝i,这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 014 篇文章,在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验,并希望进一步完善自己对整个 Java 技术体系来充实自己的技术栈的同学。与此同时,本专栏的所有文章,也都会准备充足的代码示例和完善的知识点梳理,因此也十分适合零基础的小白和要准备工作面试的同学学习。当然,我也会在必要的时候进行相关技术深度的技术解读,相信即使是拥有多年 Java 开发经验的从业者和大佬们也会有所收获并找到乐趣。

Java 集合框架中包含了多种用于数据存储和操作的类,其中 LinkedList 是一个重要且常用的实现。LinkedList 作为一个双向链表,提供了高效的插入和删除操作,特别适用于频繁进行元素增删的场景。对于很多开发者而言,深入理解 LinkedList 的特性和工作原理是提高代码性能和优化数据处理逻辑的关键。本文将对 LinkedList 进行全面的介绍和解析,帮助读者掌握其使用方法、内部原理以及源码实现。


文章目录

      • 1、LinkedList 概述
      • 2、LinkedList 的具体实现原理
        • 2.1、LinkedList 底层的数据结构
        • 2.2、LinkedList 增删改查的实现
          • 2.2.1、LinkedList 的插入
          • 2.2.2、LinkedList 的删除
          • 2.2.3、LinkedList 的修改
          • 2.2.4、LinkedList 的查询
        • 2.3、LinkedList 对链表结构的实现
      • 3、LinkedList 相关知识点
        • 3.1、关于 Queue 队列
        • 3.2、关于 ArrayList 和 LinkedList 的区别
        • 3.3、算法:翻转链表
      • 4、LinkedList 的使用(常用方法)
        • 4.1、LinkedList 的常用方法
        • 4.2、继承自 `Queue` 接口的方法
        • 4.3、Collections 类中涉及 LinkedList 的常用方法


1、LinkedList 概述

LinkedList 是 List 接口的一个实现,它是一个双向链表。与 ArrayList 相比,LinkedList 的元素在内存中不是连续存放的。每个元素(称为节点)都包含两部分数据:一部分是存储的数据,另一部分是指向前一个节点和后一个节点的链接(指针)。

LinkedList 的优点在于插入和删除元素时效率很高。因为链表的数据结构使得它只需要修改前后节点的指针即可,而不需要像 ArrayList 那样移动其他元素。因此,LinkedList 适合用在需要频繁执行添加和删除操作的场景。

然而,LinkedList 的随机访问效率不高,每次查找某个元素都需要从头开始遍历链表直到找到目标元素。这使得 LinkedList 在执行随机访问操作时速度较慢,不如 ArrayList。

在 Java 中,LinkedList 除了实现 List 接口外,还实现了 Deque 接口,这意味着它还可以被当作队列(Queue)、双端队列(Deque)使用,提供了更加丰富的方法,如 addFirst(), addLast(), removeFirst(), removeLast() 等。

LinkedList 也是非线程安全的。如果在多线程环境中使用,需要外部同步或者考虑使用 java.util.concurrent 包中的线程安全类,如 LinkedBlockingDeque 等。

总的来说,LinkedList 由于其结构的特点,适合于数据量不大但插入和删除操作频繁的场景,而不适合大量的随机访问操作。


2、LinkedList 的具体实现原理

2.1、LinkedList 底层的数据结构

LinkedList 是基于链表数据结构实现的,它包含一系列的节点(Node),每个节点包括三个部分:前一个节点的引用(previous),储存的元素(data),和下一个节点的引用(next)。这种数据结构支持高效的元素插入和删除操作。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{transient int size = 0;// 链表中元素的数量transient int size = 0;/*** 指向第一个节点的指针*/transient Node<E> first;/*** 指向最后一个节点的指针*/transient Node<E> last;/*** 构造一个空的链表*/public LinkedList() {}/*** 构造一个包含指定集合元素的链表,这些元素按集合的迭代器返回的顺序排列。** @param  c 要放入链表中的集合* @throws NullPointerException 如果指定的集合为 null*/public LinkedList(Collection<? extends E> c) {this();// 将集合中的所有元素添加到链表中addAll(c);}// 省略其他方法和实现细节.../*** Node 是一个私有的静态内部类,用于表示 LinkedList 中的每个节点** @param <E>*/private static class Node<E> {// 节点存储的元素E item;// 指向下一个节点的引用Node<E> next;// 指向前一个节点的引用Node<E> prev;/*** 构造方法,创建一个新的节点** @param prev    该节点的前一个节点* @param element 该节点存储的元素* @param next    该节点的后一个节点*/Node(Node<E> prev, E element, Node<E> next) {// 设置节点存储的元素this.item = element;// 设置指向下一个节点的引用this.next = next;// 设置指向前一个节点的引用this.prev = prev;}}// 省略其他方法和实现细节...
}
2.2、LinkedList 增删改查的实现
2.2.1、LinkedList 的插入

LinkedList 的插入的实现并不复杂,其插入式,主要会有两种场景,一种是在链表的末尾插入,另一种是在指定节点之前插入一个新节点,二者的实现都是通过创建一个新节点并更新其前驱和后继节点的引用,唯一的区别就是,linkBefore 是在指定节点之后插入该新节点,而 linkAfter 是在指定节点之后插入该新节点。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 在链表末尾添加一个元素** @param e 要添加的元素* @return 总是返回 true*/@Overridepublic boolean add(E e) {// 在链表末尾链接一个新的节点linkLast(e);return true;}/*** 在链表末尾链接一个新的节点** @param e 新节点存储的元素*/void linkLast(E e) {// 保存当前链表的最后一个节点final Node<E> l = last;// 创建一个新的节点,前驱节点是当前最后一个节点,后继节点是 nullfinal Node<E> newNode = new Node<>(l, e, null);// 将链表的最后一个节点更新为新节点last = newNode;if (l == null)// 如果链表之前是空的,即没有任何元素// 将新节点设置为链表的第一个节点first = newNode;else// 如果链表中已有元素// 将原最后一个节点的 next 指针指向新节点l.next = newNode;// 链表大小增加 1size++;  }/*** 在指定索引处插入元素** @param index 要插入元素的位置* @param element 要插入的元素*/public void add(int index, E element) {checkPositionIndex(index);if (index == size)linkLast(element);elselinkBefore(element, node(index));}/*** 在指定节点之前插入一个新节点** @param e 新节点存储的元素* @param succ 指定的节点,新节点将插入在其之前*/void linkBefore(E e, Node<E> succ) {// assert succ != null;  // 确保 succ 不为 null,确保在调用该方法前 succ 一定存在// 保存指定节点的前驱节点final Node<E> pred = succ.prev;// 创建一个新的节点,其前驱是 pred,后继是 succfinal Node<E> newNode = new Node<>(pred, e, succ);// 将指定节点的前驱更新为新节点succ.prev = newNode;if (pred == null)// 如果 pred 为 null,说明 succ 是第一个节点// 将新节点设置为链表的第一个节点first = newNode;else// 如果 pred 不为 null,说明 succ 不是第一个节点// 将 pred 的后继节点更新为新节点pred.next = newNode;// 链表大小增加 1size++;// 修改计数器增加 1,用于快速失败机制modCount++;  }// 省略其他方法和实现细节...
}

此外,另一个十分值得注意的点是,add(int index, E element) 在调用指定节点之前插入一个新节点方法时,调用了 node(int index) 方法来返回指定索引处的节点。该方法可以看作是 LinkedList 的核心实现之一,除插入方法之外,LinkedList 在查询、删除、修改等方法除也需要调用当前方法:

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 返回指定索引处的节点。** @param index 要获取节点的位置* @return 指定索引处的节点*/Node<E> node(int index) {// assert isElementIndex(index);  // 确保索引在有效范围内// 判断索引是否在链表的前半部分if (index < (size >> 1)) {// 从链表的第一个节点开始遍历Node<E> x = first;// 遍历到指定索引位置for (int i = 0; i < index; i++)// 依次移动到下一个节点x = x.next;// 返回找到的节点return x;} else {// 索引在链表的后半部分Node<E> x = last;// 从链表的最后一个节点开始遍历for (int i = size - 1; i > index; i--)// 依次移动到前一个节点x = x.prev;// 返回找到的节点return x;}}// 省略其他方法和实现细节...
}
2.2.2、LinkedList 的删除

LinkedList 的删除的实现同样十分简单,是使用 unlink 方法,即通过更新前驱和后继节点的引用,移除指定节点并返回其存储的元素实现的。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 解除并移除指定节点。** @param x 要移除的节点* @return 被移除节点存储的元素*/E unlink(Node<E> x) {// assert x != null;  // 确保 x 不为 null// 保存节点中的元素final E element = x.item;// 保存节点的后继节点final Node<E> next = x.next;// 保存节点的前驱节点final Node<E> prev = x.prev;if (prev == null) {// 如果前驱节点为 null,说明 x 是第一个节点// 将链表的第一个节点更新为 x 的后继节点first = next;} else {// 如果前驱节点不为 null// 将前驱节点的后继更新为 x 的后继节点prev.next = next;// 将 x 的前驱设为 null,帮助垃圾回收x.prev = null;}if (next == null) {// 如果后继节点为 null,说明 x 是最后一个节点// 将链表的最后一个节点更新为 x 的前驱节点last = prev;} else {// 如果后继节点不为 null// 将后继节点的前驱更新为 x 的前驱节点next.prev = prev;// 将 x 的后继设为 null,帮助垃圾回收x.next = null;}// 将 x 中的元素设为 null,帮助垃圾回收x.item = null;// 链表大小减 1size--;// 修改计数器增加 1,用于快速失败机制modCount++;// 返回被移除节点中的元素return element;}/*** 移除指定索引处的元素。** @param index 要移除元素的位置* @return 被移除的元素*/public E remove(int index) {checkElementIndex(index);return unlink(node(index));}/*** 从链表中移除第一次出现的指定元素(如果存在)。* 如果列表不包含该元素,则不做改变。** @param o 要移除的元素* @return 如果列表包含指定元素并移除成功则返回 true,否则返回 false*/public boolean remove(Object o) {// 如果要移除的元素为 nullif (o == null) { for (Node<E> x = first; x != null; x = x.next) {// 从链表的第一个节点开始遍历if (x.item == null) {// 如果当前节点的元素为 nullunlink(x);  // 解除并移除当前节点// 返回 true,表示移除成功return true;  }}} else {  // 如果要移除的元素不为 nullfor (Node<E> x = first; x != null; x = x.next) {  // 从链表的第一个节点开始遍历// 如果当前节点的元素等于要移除的元素if (o.equals(x.item)) {// 解除并移除当前节点unlink(x);// 返回 true,表示移除成功return true;  }}}// 如果没有找到要移除的元素,返回 falsereturn false;  }// 省略其他方法和实现细节...
}
2.2.3、LinkedList 的修改

LinkedList 对于修改的则是通过找到原位置的 Node 并修改其 item 值实现的。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 替换指定索引处的元素,并返回被替换的元素。** @param index 要替换元素的位置* @param element 要设置的新元素* @return 被替换的旧元素* @throws IndexOutOfBoundsException 如果索引超出范围*/public E set(int index, E element) {// 检查索引是否在范围内checkElementIndex(index);// 获取指定索引处的节点Node<E> x = node(index);// 保存当前节点的旧元素E oldVal = x.item;// 将节点的元素设置为新元素x.item = element;// 返回被替换的旧元素return oldVal;}/*** 将迭代器返回的最后一个元素替换为指定的元素。** @param e 要设置的新元素* @throws IllegalStateException 如果没有调用 next() 或 previous() 方法*/public void set(E e) {if (lastReturned == null)// 如果 lastReturned 为 null,表示未调用 next() 或 previous()// 抛出非法状态异常throw new IllegalStateException();// 检查是否发生并发修改checkForComodification();// 将 lastReturned 节点的元素设置为新元素 elastReturned.item = e;}// 省略其他方法和实现细节...
}
2.2.4、LinkedList 的查询

LinkedList 的查询即获取指定索引处的元素。它的实现同前面的其他方法获取索引处元素一样,依赖 node(int index) 方法。

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 获取指定索引处的元素** @param index 要获取元素的位置* @return 指定索引处的元素*/public E get(int index) {checkElementIndex(index);return node(index).item;}/*** 返回指定索引处的节点。** @param index 要获取节点的位置* @return 指定索引处的节点*/Node<E> node(int index) {// assert isElementIndex(index);  // 确保索引在有效范围内// 判断索引是否在链表的前半部分if (index < (size >> 1)) {// 从链表的第一个节点开始遍历Node<E> x = first;// 遍历到指定索引位置for (int i = 0; i < index; i++)// 依次移动到下一个节点x = x.next;// 返回找到的节点return x;} else {// 索引在链表的后半部分Node<E> x = last;// 从链表的最后一个节点开始遍历for (int i = size - 1; i > index; i--)// 依次移动到前一个节点x = x.prev;// 返回找到的节点return x;}}// 省略其他方法和实现细节...
}
2.3、LinkedList 对链表结构的实现

LinkedList 类实现了 Queue 接口,因此提供了队列相关的方法。这些方法允许 LinkedList 作为一个双端队列(Deque)使用,支持在队列的头部和尾部进行插入和删除操作。下面是对 LinkedList 中与 Queue 相关方法的概括说明:

  • offer(E e):将指定的元素添加到队列的尾部并返回 true。实现:调用 linkLast(E e) 方法,将元素添加到链表的尾部;
  • poll():获取并移除此队列的头部,如果队列为空,则返回 null。实现:调用 unlinkFirst(Node<E> f) 方法,移除并返回链表的第一个元素;
  • remove():获取并移除此队列的头部,如果队列为空,则抛出 NoSuchElementException。实现:调用 unlinkFirst(Node<E> f) 方法,移除并返回链表的第一个元素。如果链表为空,抛出 NoSuchElementException
  • peek():获取但不移除此队列的头部;如果队列为空,则返回 null。实现:返回链表的第一个元素 first.item,如果链表为空返回 null
  • element():获取但不移除此队列的头部;如果队列为空,则抛出 NoSuchElementException。实现:返回链表的第一个元素 first.item,如果链表为空抛出 NoSuchElementException

具体实现:

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 将指定的元素添加到队列的尾部。** @param e 要添加的元素* @return 添加成功返回 true*/public boolean offer(E e) {// 调用 add 方法,将元素添加到链表的尾部return add(e);}/*** 获取并移除此队列的头部,如果队列为空,则返回 null。** @return 队列头部的元素,如果队列为空则返回 null*/public E poll() {// 保存链表的第一个节点final Node<E> f = first;// 如果链表为空返回 null,否则移除并返回第一个元素return (f == null) ? null : unlinkFirst(f);}/*** 获取并移除此队列的头部,如果队列为空,则抛出 NoSuchElementException。** @return 队列头部的元素* @throws NoSuchElementException 如果队列为空*/public E remove() {// 保存链表的第一个节点final Node<E> f = first;// 如果链表为空,抛出 NoSuchElementExceptionif (f == null)throw new NoSuchElementException();// 移除并返回第一个元素return unlinkFirst(f);}/*** 获取但不移除此队列的头部;如果队列为空,则返回 null。** @return 队列头部的元素,如果队列为空则返回 null*/public E peek() {// 保存链表的第一个节点final Node<E> f = first;// 返回第一个元素但不移除,如果链表为空返回 nullreturn (f == null) ? null : f.item;}/*** 获取但不移除此队列的头部;如果队列为空,则抛出 NoSuchElementException。** @return 队列头部的元素* @throws NoSuchElementException 如果队列为空*/public E element() {return getFirst();}/*** 返回链表的第一个元素;如果链表为空,则抛出 NoSuchElementException。** @return 链表的第一个元素* @throws NoSuchElementException 如果链表为空*/public E getFirst() {// 保存链表的第一个节点final Node<E> f = first;// 如果链表为空,抛出 NoSuchElementExceptionif (f == null)throw new NoSuchElementException();// 返回第一个元素return f.item;}// 省略其他方法和实现细节...
}

内部辅助方法,unlinkFirst(Node<E> f):移除并返回链表的第一个节点。实现:更新链表的头节点 first 为当前头节点 f 的下一个节点 f.next,并将旧头节点的前驱引用设为 null

public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{// 省略其他方法和实现细节.../*** 移除并返回链表的第一个节点。** @param f 要移除的第一个节点* @return 被移除节点存储的元素*/private E unlinkFirst(Node<E> f) {// 保存第一个节点的元素final E element = f.item;// 保存第一个节点的后继节点final Node<E> next = f.next;// 清空第一个节点的元素f.item = null;// 清空第一个节点的后继引用,帮助垃圾回收f.next = null;// 更新链表的头节点为原头节点的后继节点first = next;// 如果新的头节点为 null,说明链表现在为空if (next == null) {// 更新链表的尾节点为 nulllast = null;} else {// 将新的头节点的前驱引用设为 nullnext.prev = null;}// 链表大小减 1size--;// 修改计数器增加 1,用于快速失败机制modCount++;// 返回被移除的元素return element;}// 省略其他方法和实现细节...
}

3、LinkedList 相关知识点

3.1、关于 Queue 队列

队列(Queue):也是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。向队列中插入元素称为入队或进队;删除元素称为出队或离队。

image-20240611154341484

这和我们日常生活中的排队是一致的,最早排队的也是最早离队的。其操作的特性是先进先出(First In First Out, FIFO),故又称为先进先出的线性表。基本上,一个队列就是一个先入先出(FIFO)的数据结构

在Java 中 Queue 接口与 List、Set 同一级别,都是继承了 Collection 接口。LinkedList 实现了 Deque 接口。

3.2、关于 ArrayList 和 LinkedList 的区别

ArrayListLinkedList 都是 List 接口的实现,但它们在内部数据结构和性能上有一些区别:

  1. 内部数据结构:ArrayList 是基于动态数组实现的,支持随机访问,按索引访问元素非常快,时间复杂度为 O(1)。LinkedList 是基于双向链表实现的,不支持高效的随机访问,按索引访问元素需要从头(或尾)开始遍历,时间复杂度为 O(n)。
  2. 插入和删除:ArrayList 的插入和删除操作需要进行数组元素的移动(除非插入和删除操作在列表末尾进行),所以插入和删除元素的时间复杂度为 O(n)。LinkedList 的插入和删除操作只需要改变节点的引用,所以在列表中间插入和删除元素的时间复杂度为 O(1)(前提是已经获取到了要插入位置的节点)。
  3. 内存占用:ArrayList 的内存占用相对较低,因为它只需要存储元素数据和数组的引用。LinkedList 的内存占用较高,因为它需要额外存储节点之间的引用。

总的来说,ArrayList 更适合随机访问场景,LinkedList 更适合插入和删除操作频繁的场景。

3.3、算法:翻转链表

假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。

在遍历链表时,将当前节点的 next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。

class Solution {/*** 反转链表。** @param head 链表的头节点* @return 反转后的链表的头节点*/public ListNode reverseList(ListNode head) {// 初始化前一个节点为 nullListNode prev = null;// 初始化当前节点为头节点ListNode curr = head;// 遍历链表直到当前节点为 nullwhile (curr != null) {// 保存当前节点的下一个节点ListNode next = curr.next;// 将当前节点的下一个节点指向前一个节点,完成反转curr.next = prev;// 将前一个节点更新为当前节点prev = curr;// 将当前节点更新为下一个节点curr = next;}// 返回反转后的链表头节点return prev;}
}

4、LinkedList 的使用(常用方法)

下面是对 LinkedList 的常用方法和 Collections 类中的一些涉及 LinkedList 的方法进行详细介绍:

4.1、LinkedList 的常用方法
  1. add(E e)
  • 功能:将元素添加到链表的末尾。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
  1. add(int index, E element)
  • 功能:在指定位置插入元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
list.add(1, "Orange"); // 将 "Orange" 插入在 "Banana" 前面
  1. remove(Object o)
  • 功能:删除链表中首次出现的指定元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
list.remove("Apple");
  1. remove(int index)
  • 功能:删除指定索引处的元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
list.remove(0); // 删除 "Apple"
  1. get(int index)
  • 功能:返回链表中指定位置的元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
String item = list.get(0); // 获取第一个元素 "Apple"
  1. set(int index, E element)
  • 功能:替换指定位置的元素,并返回旧值。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
String oldItem = list.set(0, "Orange"); // 将 "Apple" 替换为 "Orange"
  1. size()
  • 功能:返回链表中的元素数量。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
int size = list.size(); // size 为 1
  1. isEmpty()
  • 功能:检查链表是否为空。
  • 用例:
LinkedList<String> list = new LinkedList<>();
boolean empty = list.isEmpty(); // 判断链表是否为空
  1. clear()
  • 功能:清空链表中的所有元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.clear(); // 清空链表
  1. contains(Object o)
  • 功能:检查链表是否包含指定的元素。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
boolean contains = list.contains("Apple"); // 检查是否包含 "Apple"
  1. indexOf(Object o)lastIndexOf(Object o)
  • 功能:返回指定元素首次出现和最后一次出现的索引位置。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple");
int firstIndex = list.indexOf("Apple"); // 返回 0
int lastIndex = list.lastIndexOf("Apple"); // 返回 2
  1. toArray()
  • 功能:将链表中的元素转换为数组。
  • 用例:
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
Object[] array = list.toArray(); // 转换为数组
  1. addAll(Collection<? extends E> c)
  • 功能:将指定集合中的所有元素添加到链表的尾部。
  • 用例:
LinkedList<Integer> list = new LinkedList<>();
LinkedList<Integer> newElements = new LinkedList<>(Arrays.asList(1, 2, 3));
list.addAll(newElements);  // 添加多个元素
  1. addAll(int index, Collection<? extends E> c)
  • 功能:将指定集合中的所有元素添加到链表中的指定位置。
  • 用例:
LinkedList<String> list = new LinkedList<>(Arrays.asList("a", "b", "c"));
LinkedList<String> newElements = new LinkedList<>(Arrays.asList("x", "y"));
list.addAll(1, newElements);  // 在索引1的位置添加多个元素
  1. removeAll(Collection<?> c)
  • 功能:从链表中移除指定集合中也存在的所有元素。
  • 用例:
LinkedList<String> list = new LinkedList<>(Arrays.asList("a", "b", "c", "b"));
list.removeAll(Collections.singleton("b"));  // 移除所有 "b"
  1. retainAll(Collection<?> c)
  • 功能:仅保留链表中那些也包含在指定集合中的元素。
  • 用例:
LinkedList<String> list = new LinkedList<>(Arrays.asList("a", "b", "c"));
list.retainAll(Arrays.asList("a", "b"));  // 保留 "a" 和 "b"
  1. containsAll(Collection<?> c)
  • 功能:如果链表包含指定集合中的所有元素,则返回 true
  • 用例:
LinkedList<String> list = new LinkedList<>(Arrays.asList("a", "b", "c"));
boolean contains = list.containsAll(Arrays.asList("a", "b"));  // 检查是否包含 "a" 和 "b"
4.2、继承自 Queue 接口的方法
  1. offer(E e)
  • 功能:将指定的元素添加到队列的尾部。
  • 用例:
LinkedList<String> queue = new LinkedList<>();
queue.offer("Apple");
  1. poll()
  • 功能:获取并移除队列的头部元素,如果队列为空,则返回 null
  • 用例:
LinkedList<String> queue = new LinkedList<>();
queue.offer("Apple");
String item = queue.poll(); // 获取并移除 "Apple"
  1. remove()
  • 功能:获取并移除队列的头部元素,如果队列为空,则抛出 NoSuchElementException
  • 用例:
LinkedList<String> queue = new LinkedList<>();
queue.offer("Apple");
String item = queue.remove(); // 获取并移除 "Apple"
  1. peek()
  • 功能:获取但不移除队列的头部元素,如果队列为空,则返回 null
  • 用例:
LinkedList<String> queue = new LinkedList<>();
queue.offer("Apple");
String item = queue.peek(); // 获取但不移除 "Apple"
  1. element()
  • 功能:获取但不移除队列的头部元素,如果队列为空,则抛出 NoSuchElementException
  • 用例:
LinkedList<String> queue = new LinkedList<>();
queue.offer("Apple");
String item = queue.element(); // 获取但不移除 "Apple"
4.3、Collections 类中涉及 LinkedList 的常用方法
  1. sort(List<T> list)
  • 功能:对链表进行排序(自然顺序)。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(3, 1, 4, 1, 5));
Collections.sort(list); // 对链表排序
  1. reverse(List<?> list)
  • 功能:反转链表中元素的顺序。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 3));
Collections.reverse(list); // 链表变为 [3, 2, 1]
  1. shuffle(List<?> list)
  • 功能:随机打乱链表中元素的顺序。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 3));
Collections.shuffle(list); // 打乱链表元素的顺序
  1. binarySearch(List<? extends Comparable<? super T>> list, T key)
  • 功能:在已排序的链表中使用二分查找法查找指定元素的索引。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 3, 4, 5));
Collections.sort(list);
int index = Collections.binarySearch(list, 3); // 在链表中查找数字 3 的索引
  1. copy(List<? super T> dest, List<? extends T> src)
  • 功能:将一个链表中的所有元素复制到另一个链表中。
  • 用例:
LinkedList<Integer> src = new LinkedList<>(Arrays.asList(1, 2, 3));
LinkedList<Integer> dest = new LinkedList<>(Arrays.asList(5, 6, 7, 8));
Collections.copy(dest, src); // 将 src 复制到 dest
  1. fill(List<? super T> list, T obj)
  • 功能:使用指定元素替换链表中的所有元素。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 3));
Collections.fill(list, 0); // 将链表中的所有元素替换为 0
  1. addAll(Collection<? super T> c, T... elements)
  • 功能:向集合中添加多个元素。
  • 用例:
LinkedList<Integer> list = new LinkedList<>();
Collections.addAll(list, 1, 2, 3, 4);  // 向链表中添加多个元素
  1. replaceAll(List<T> list, T oldVal, T newVal)
  • 功能:替换链表中所有的旧值为新值。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 1, 3));
Collections.replaceAll(list, 1, 99);  // 将所有1替换为99
  1. frequency(Collection<?> c, Object o)
  • 功能:返回指定元素在集合中出现的次数。
  • 用例:
LinkedList<Integer> list = new LinkedList<>(Arrays.asList(1, 2, 1, 3));
int freq = Collections.frequency(list, 1);  // 计算1在链表中出现的次数
  1. disjoint(Collection<?> c1, Collection<?> c2)
  • 功能:如果两个集合没有共同的元素,则返回 true。
  • 用例:
LinkedList<Integer> list1 = new LinkedList<>(Arrays.asList(1, 2, 3));
LinkedList<Integer> list2 = new LinkedList<>(Arrays.asList(4, 5, 6));
boolean isDisjoint = Collections.disjoint(list1, list2);  // 检查两个链表是否没有共同元素

通过以上方法,可以对 LinkedList 进行各种常用操作,如添加、删除、获取元素等,以及使用 Collections 类中的方法对 LinkedList 进行排序、反转、打乱顺序等批量操作。特别是继承自 Queue 接口的方法,可以使 LinkedList 作为队列使用,提供了队列相关的操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/28701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI大模型在运动项目的深度融合和在穿戴设备的实践及未来运动健康技术发展

文章目录 1. 技术架构2. 模型选择2.1 LSTM&#xff08;长短期记忆网络&#xff09;2.2 CNN&#xff08;卷积神经网络&#xff09;2.3 Transformer 3. 数据处理数据预处理 4. 实时性要求4.1 边缘计算4.2 模型优化 5. 数据隐私与安全6. 深入分析AI大模型在穿戴设备的应用和未来发…

计算机专业的未来展望

身份角度一&#xff1a;一名曾经的计算机专业学生  作为一名曾经的计算机专业学生&#xff0c;我认为计算机相关专业仍然是一个值得考虑的选择。随着科技的飞速发展&#xff0c;计算机行业的需求只会越来越高&#xff0c;因此&#xff0c;无论是在就业前景还是个人发展方面&a…

CD4069做陶瓷和晶体振荡器的试验初步

在面包板上面&#xff0c;供电5v。尝试用4069做晶体振荡器 465K&#xff0c;1M陶瓷&#xff0c;不起振 4M陶瓷&#xff0c;不起振&#xff0c;在1脚加上68pf电容后起振&#xff0c;但幅度没有后面写的10M陶瓷和17.6的晶振的幅度大 10M陶瓷&#xff0c;起振ok 16M陶瓷&#…

【面试干货】String、StringBuilder、StringBuffer 的区别

【面试干货】String、StringBuilder、StringBuffer 的区别 1、String2、StringBuffer3、StringBuilder4、性能对比5、使用建议 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;String、StringBuilder和StringBuffer是用…

Linux经典常见常用命令50条

文章目录 基础命令1. ls2. cd3. pwd4. cp5. mv6. rm7. echo8. cat9. head10. tail 系统信息与管理命令11. ps12. top13. htop14. kill15. df16. du17. uname18. hostname19. uptime20. who21. man 文件权限与所有权命令22. chmod23. chown 网络管理命令24. ping25. ifconfig26.…

MySQL面试重点-1

1. 数据库基础知识&#xff1a; DDL、DML、DQL、DCL的概念与区别&#xff1f; DDL&#xff08;数据定义语言&#xff09;&#xff1a;创建&#xff08;CREATE&#xff09;数据库中的各种对象&#xff1a;表、视图、索引等DML&#xff08;数据操纵语言&#xff09;&#xff1a…

Vue53-Todo-list案例

一、需求&#xff1a; 二、组件的划分&#xff1a;按照功能划分 组件起名&#xff0c;不要和html内置元素重名&#xff01; Vue鼓励组件名用多个单词。 三、组件化编码流程 3-1、实现静态组件 将各个组件的基本框架写好&#xff0c;并在App.vue文件中进行引入和注册。 将已有…

[Day 8] 區塊鏈與人工智能的聯動應用:理論、技術與實踐

智能合約與去中心化應用 智能合約&#xff08;Smart Contracts&#xff09;是一種基於區塊鏈技術的程式碼&#xff0c;旨在自動執行、驗證或執行合約的內容或執行條款。透過智能合約&#xff0c;合約中的各方可以在無需第三方信任的情況下進行交易&#xff0c;實現自動化、透明…

AI数据分析:集中度分析和离散度分析

在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个Python脚本编写的任务&#xff0c;具体步骤如下&#xff1a; 读取Excel表格&#xff1a;"F:\AI自媒体内容\AI行业数据分析\toolify月榜\toolify2023年-2024年月排行榜汇总数据.xlsx&qu…

UniVue第一个版本发布说明

今天终于发布第一个版本了&#xff0c;爆肝了这么多天&#xff0c;对之前的代码优化重构&#xff0c;今天终于做完了&#xff0c;第一个版本的核心基础功能已经全部完成&#xff01; github仓库 稳定版本仓库&#xff1a;https://github.com/Avalon712/UniVue 开发版本仓库&…

196. 删除重复的电子邮箱

196. 删除重复的电子邮箱 题目链接&#xff1a;196. 删除重复的电子邮箱 代码如下&#xff1a; # Write your MySQL query statement below delete from Person as p where p.id not in(select e.id from (select min(id) as idfrom Person group by email ) as e )

(二十一)Java 之多态

目录 一. 前言 二. 多态 2.1. 实例入手 2.2. 虚方法 三. 多态的实现方式 四. 课后习题 一. 前言 多态是同一个行为具有多个不同表现形式或形态的能力。 多态性是对象多种表现形式的体现。 比如我们说“宠物”这个对象&#xff0c;它就有很多不同的表达或实现&#xff0c;…

web前端五行属性:深入探索与实战解析

web前端五行属性&#xff1a;深入探索与实战解析 在Web前端开发中&#xff0c;五行属性这一概念或许听起来有些陌生。然而&#xff0c;如果我们将其与前端开发的核心理念相结合&#xff0c;就能发现其中蕴含的深刻内涵。本文将从四个方面、五个方面、六个方面和七个方面&#…

QT图片转PNG项目实战(含源码)

一、需求说明 最近在换工作,都需要将所有的图片,例如身份证、毕业证等信息都需要合并到一个pdf中。找了软件发现几乎都需要收费,干脆就自己写一个好了。 功能说明如下: 支持鼠标拖动加载图片,可以从桌面将图片类型的文件拖到软件中,一次最多添加150张。支持点击菜单中的…

树莓派4B刷入KODI作为机顶盒

LibreELEC Raspberry - LibreELEC Download - OSMC 使用LibreELEC USB-SD Creator进行系统烧写&#xff0c; LibreELEC USB-SD Creator下载地址 因为Kodi语言包是以插件的形式存在&#xff0c;不是集成到安装包里&#xff0c;有时候网络原因不能连接到Kodi的服务器&#xff…

爬虫初学篇

初次学习爬虫&#xff0c;知识笔记小想 目录&#x1f31f; 一、&#x1f349;基础知识二、&#x1f349;http协议&#xff1a;三、&#x1f349;解析网页(1) xpath的用法&#xff1a;(2) bs4解析器的解释&#xff1a;(3) python字符编码的错误&#xff1a;(4) 正则表达式&#…

如何在单个VPS上使用nginx、forever和crontab托管多个Node.js应用

遵循本教程的要求 您需要安装 nginx 和 Node.js&#xff0c;并且在 DigitalOcean 上已经有关于这些主题的教程&#xff1a; 如何安装 nginx 和 如何安装 Node.js。 此外&#xff0c;您应该已经拥有一个域名&#xff0c;以便将正在运行的 Node.js 服务映射到域名&#xff0c;而…

手把手教学!新一代 Kaldi: TTS Runtime ASR 实时本地语音识别 语音合成来啦

简介 本文向大家介绍如何在新一代 Kaldi的部署框架 **sherpa-onnx**中使用 TTS。 注:sherpa-onnx 提供的是一个TTS runtime, 即部署环境。它并不支持模型训练。 本文使用的测试模型,都是来源于网上开源的 VITS 预训练模型。 我们提供了 ONNX 导出的支持。如果你也有 VITS 预…

你应该知道的口语连读技巧

[共24课]连读弱读-发音课程已上线 第一课 辅音和元音的连读 linking consonant to vowel 辅音和元音连读 第二课 h和th的删除不读 h-删除|deletion|elision|drop he/her/have/here/him... them-->/əm/ 第三课 t的删去不读(1) t-deletion|elision(1) drop t after…

GEO ISP图像调试-PFC(蓝紫边校正)

目录 1、简单介绍 2、调试策略 3、输出结果 1、简单介绍 GEO中中调整图像蓝紫边可分为两步&#xff0c;第一步&#xff1a;调整蓝紫边检测区域&#xff0c;第二步&#xff1a;设置去蓝紫边强度。 2、调试策略 图1 该图像蓝紫边较严重 主要原因是由于蓝紫边检测不准导致的&…