【Java从入门到放弃 之 LinkedList 和 ArrayDeque】

LinkedList 和 ArrayDeque

LinkedList

LinkedList 是 Java 集合框架中的一个类,它实现了 List 接口和 Deque(双端队列)接口。与 ArrayList 不同,LinkedList 使用双向链表来存储元素,这意味着每个元素(节点)都包含指向前后相邻元素的引用。这种结构使得 LinkedList 在插入和删除操作上通常比基于数组的 ArrayList 更高效,但在随机访问方面则不如后者。

LinkedList 详细介绍

  1. 概述
    定义:LinkedList 是一个可以动态调整大小的双向链表实现,允许在列表两端快速添加或移除元素,并且支持按位置插入和删除。
    特点:
  • 线程不安全:与 ArrayList 类似,LinkedList 也不是同步的,多线程环境下需要额外的同步机制。
  • 允许重复元素:可以包含多个相同的元素。
  • 允许空值:支持存储 null 值,甚至可以存储多个 null。
  • 双端队列功能:除了作为普通列表使用外,LinkedList 还提供了双端队列的功能,如在头部或尾部添加/移除元素。
  1. 内部工作原理
    LinkedList 内部维护了一个双向链表的数据结构,其中每个节点(Node)包含三个部分:
  • 元素本身(item)
  • 前驱节点(prev)
  • 后继节点(next)

源码如下:

java 复制代码
    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

基本用法

java 复制代码
    void addFirst(E e);
    void addLast(E e);
    E getFirst();
    E getLast();
    boolean offerFirst(E e);
    boolean offerLast(E e);
    E peekFirst();
    E peekLast();
    E pollFirst();
    E pollLast();
    E removeFirst();
    E removeLast();

实现原理

java 复制代码
    transient int size = 0;

    /**
     * Pointer to first node.
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     */
    transient Node<E> last;

我们去看LinkedList的源码,我们会发现,LinkedList由三个成员变量,一个是size代表list由多少元素;一个是头节点,一个是尾节点。

而Node的本身定义相当于一个元素存储数据,一个存储前序节点,一个存储后序节点。

java 复制代码
        LinkedList<Integer> linkedList = new LinkedList<>();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);

示例图:

这段代码对应的底层node的示例如下:

总结

用法上,LinkedList是一个List,但也实现了Deque接口,可以作为队列、栈和双端队列使用。实现原理上,LinkedList内部是一个双向链表,并维护了长度、头节点和尾节点,这决定了它有如下特点。

  1. 自由分配空间
  2. 不支持随机访问
  3. 查找对应内容都需要遍历列表
  4. 在两端添加、删除元素的效率很高,时间复杂度为O(1)。
  5. 在中间插入、删除元素,要先找到修改的位置,查找的时间复杂度为O(N),但修改本身的效率很高,效率为O(1)。

知道了LinkedList的底层实现,我们就知道,如果经常需要添加删除元素,且经常需要从两端操作,就可以考虑使用LinkedList。

ArrayDeque

我们上面介绍了LinkedList,它实现了Queue接口与Deque接口。还有一个ArrayDeque也实现了Deques接口而且底层使用数组实现的,我们知道deque需要操作两端的数据,按照之前的数组操作的话,会频繁引动数据,但是ArrayDeque的效率却非常高。我们简单介绍一下它的原理。

java 复制代码
public class ArrayDeque<E> extends AbstractCollection<E>
                           implements Deque<E>, Cloneable, Serializable{

    transient Object[] elements;


    transient int head;


    transient int tail;


    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
 }

我们打开它的源码,会发现它的成员变量有一个head,另一个tail。elements是实际存储元素的数组。那么为什么它对两端操作的效率就那么高呢?
因为它通过使用head和tail 把一个数组编程逻辑上的循环数组,而且数组的长度一般设置为2的整数次幂,方便进行位操作

相关推荐
高兴达2 分钟前
RPC--Netty客户端实现
java·spring·rpc
苦夏木禾23 分钟前
js请求避免缓存的三种方式
开发语言·javascript·缓存
重庆小透明28 分钟前
力扣刷题记录【1】146.LRU缓存
java·后端·学习·算法·leetcode·缓存
超级土豆粉31 分钟前
Turndown.js: 优雅地将 HTML 转换为 Markdown
开发语言·javascript·html
lang2015092833 分钟前
Reactor操作符的共享与复用
java
TTc_44 分钟前
@Transactional事务注解的批量回滚机制
java·事务
wei_shuo2 小时前
飞算 JavaAI 开发助手:深度学习驱动下的 Java 全链路智能开发新范式
java·开发语言·飞算javaai
熊猫钓鱼>_>2 小时前
用Python解锁图像处理之力:从基础到智能应用的深度探索
开发语言·图像处理·python
GO兔2 小时前
开篇:GORM入门——Go语言的ORM王者
开发语言·后端·golang·go
欧阳秦穆2 小时前
apoc-5.24.0-extended.jar 和 apoc-4.4.0.36-all.jar 啥区别
java·jar