【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的整数次幂,方便进行位操作

相关推荐
2401_cf2 小时前
为什么hadoop不用Java的序列化?
java·hadoop·eclipse
帮帮志2 小时前
idea整合maven环境配置
java·maven·intellij-idea
belldeep2 小时前
如何阅读、学习 Tcc (Tiny C Compiler) 源代码?如何解析 Tcc 源代码?
c语言·开发语言
LuckyTHP2 小时前
java 使用zxing生成条形码(可自定义文字位置、边框样式)
java·开发语言·python
无声旅者5 小时前
深度解析 IDEA 集成 Continue 插件:提升开发效率的全流程指南
java·ide·ai·intellij-idea·ai编程·continue·openapi
Blossom.1185 小时前
使用Python实现简单的人工智能聊天机器人
开发语言·人工智能·python·低代码·数据挖掘·机器人·云计算
da-peng-song5 小时前
ArcGIS Desktop使用入门(二)常用工具条——数据框工具(旋转视图)
开发语言·javascript·arcgis
galaxy_strive5 小时前
qtc++ qdebug日志生成
开发语言·c++·qt
Ryan-Joee5 小时前
Spring Boot三层架构设计模式
java·spring boot
TNTLWT5 小时前
Qt功能区:简介与安装
开发语言·qt