千家信息网

Java中LinkedList容器如何使用

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,这篇文章主要讲解了"Java中LinkedList容器如何使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Java中LinkedList容器如何使用
千家信息网最后更新 2026年11月04日Java中LinkedList容器如何使用

这篇文章主要讲解了"Java中LinkedList容器如何使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Java中LinkedList容器如何使用"吧!

    一、LinkedList的整体结构

    1.1、LinkedList的继承关系

    • public class LinkedList extends AbstractSequentialList implements List, Deque

    • LinkedList具备AbstractSequentialList的特点:AbstractSequentialList 只支持按次序访问,而不像 AbstractList 那样支持随机访问

    • LinkedList具备List的特点

    • LinkedList具备Deque的特点:Deque是一个线性collection,支持在两端插入和移除元素

    1.2、LinkedList的结构

    //元素个数transient int size = 0;//第一个元素指针transient Node first;//最后一个元素指针transient Node last;//Node节点的结构private static class Node {    E item;//当前元素    Node next;//当前元素的下一个指针    Node prev;//当前元素的上一个指针    Node(Node prev, E element, Node next) {        this.item = element;        this.next = next;        this.prev = prev;    }}
    1.2.1 Node的结构

    LinkedList特点

    1.LinkedList是通过双链表去实现的。

    2.LinkedList不存在容量不足的问题,因为是链表。

    3.LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法,所以LinkedList可以作为FIFO(先进先出)的队列;LinkedList可以作为LIFO(后进先出)的栈

    二、源码分析

    2.1、添加元素

    //添加元素public boolean add(E e) {    //默认调用,尾部添加元素的方法    linkLast(e);    return true;}//尾部添加元素void linkLast(E e) {    //记录当前尾部元素    final Node l = last;    //创建一个新的Node节点 ,prev是当前的尾节点,next指向null    final Node newNode = new Node<>(l, e, null);    //将last设置为新节点    last = newNode;    //判断当前尾部节点是否为null    if (l == null)        //当前尾部节点为null,就挂到头结点上        first = newNode;    else        //当前尾部节点不为null,就将新建的Node挂到当前last节点的next指针上        l.next = newNode;    //元素的个数+1    size++;    //LinkedList修改记录+1    modCount++;}

    新增元素add()方法默认是尾部追加,核心就是将新建的Node节点追加到当前last节点的next指针上 ,伪代码:

    Node newNode=new Node();newNode.prev=last;last.next=newNode;last=newNode;last.next=null;

    addFirst:首部追加

    public void addFirst(E e) {    linkFirst(e);}//头部追加private void linkFirst(E e) {    //记录当前首部元素    final Node f = first;    //新建一个Node节点    final Node newNode = new Node<>(null, e, f);    //首部元素指向新建的节点    first = newNode;    //判断当前首部指针是否为null    if (f == null)        //当前首部指针为null,就把新建的节点挂到last指针上        last = newNode;    else        //当前首部指针不为null,就把新建的节点挂到,当前first指针指向元素的prev指针上        f.prev = newNode;    //元素个数+1    size++;    //LinkedList修改记录+1    modCount++;}

    首部追加的逻辑与尾部追加基本相同,伪代码:

    Node newNode=new Node();newNode.next=first;first.prev=newNode;first=newNode;first.prev=null;(也可以:newNode.prev=null)

    指定位置添加元素:add(int index, E element):

    public void add(int index, E element) {    //检查要插入的位置是否合法    checkPositionIndex(index);    //如要插入的位置在最后,直接调用linkLast()    if (index == size)        linkLast(element);    else        //如要插入的位置不在最后,就先查找再插入        linkBefore(element, node(index));} //查找要插入元素的位置Node node(int index) {    // assert isElementIndex(index);    //如果要插入的位置小于集合的一半,我就从头开始找    if (index < (size >> 1)) {        Node x = first;        for (int i = 0; i < index; i++)            x = x.next;        return x;    } else {        //如果要插入的位置大于等于集合的一半,我就从尾部开始找        Node x = last;        for (int i = size - 1; i > index; i--)            x = x.prev;        return x;    }}//将新建的元素插入到查找的元素前面void linkBefore(E e, Node succ) {    // assert succ != null;    final Node pred = succ.prev;    final Node newNode = new Node<>(pred, e, succ);    succ.prev = newNode;    if (pred == null)        first = newNode;    else        pred.next = newNode;    size++;    modCount++;}

    LinkedList是一个双向链表,他只记录了头部和尾部位置,如果我们要指定位置插入,他会这么做:

    1.先遍历查找出要插入的元素位置,然后再插入;查找方式是根据 index < (size >> 1) 判断结果,决定是从头遍历,还是从尾部遍历,这种遍历方式类似于二分查找(只在第一层循环二分)

    2.新建一个Node节点,插入到查找出来的元素的前面

    由此可知为何链表对随机位置读写是不合适的;他的时间复杂度=O(n/2) ,如果n很大,我们一般就认为他的时间复杂度=O(n)

    2.2、删除元素

    //重写List的remove()public boolean remove(Object o) {    if (o == null) {        //如果要删除的元素null元素,从头开始查找这个null元素        for (Node x = first; x != null; x = x.next) {            if (x.item == null) {                unlink(x);                return true;            }        }    } else {         //如果要删除的元素不null元素,从头开始查找这个非null元素        for (Node x = first; x != null; x = x.next) {            if (o.equals(x.item)) {                unlink(x);                return true;            }        }    }    return false;}//执行删除逻辑,实质就是打断改元素与链表的引用关系E unlink(Node x) {    // assert x != null;    //记录改元素的值,实际作用就是做返回值    final E element = x.item;    //记录当前元素的下一个节点    final Node next = x.next;    //记录当前元素的上一个节点    final Node prev = x.prev;    //判断 x->prev 节点是否为null,为null就是删除头结点     if (prev == null) {        first = next;    } else {        //将 x->prev节点的next指针指向x节点的下一个节点        prev.next = next;        //将 x->prev 指针,设置为null(断开引用关系)        x.prev = null;    }     //判断 x->next 节点是否为null,为null就是删尾部结点     if (next == null) {        last = prev;    } else {        //将x->next节点的prev指针指向x->prev        next.prev = prev;        //将 x->next指针,设置为null(断开引用关系)        x.next = null;    }    //将x的值设置为null    x.item = null;    //集合大小-1    size--;    //集合的修改记录-1    modCount++;    return element;}

    这里我们看到LinkedList重写了List的remove方法,整个删除逻辑也是先查找再删除,时间复杂度O(n),如果是删除首部元素时间复杂度=O(1),若要删除尾部元素请使用removeLast( )

    • LinkedLis删除首部元素:removeFirst()

    • LinkedLis删除尾部元素:removeLast()

    • LinkedLis首部出队:pollFirst( ) ,队列的特点

    • LinkedLit尾部出队:pollLast( ),队列的特点

    2.3、迭代器

    Iterator迭代器只能是从头往尾迭代,而LinkedList是双向链表,他还可以从尾往头部迭代,JAVA提供了一个新的迭代器接口:

    public interface ListIterator extends Iterator{    //判断是否存在下一个元素    boolean hasNext();    //获取下一个元素    E next();    //判断是否还有前一个元素    boolean hasPrevious();    //获取前一个元素    E previous();}

    LinkedList实现该接口:

    private class ListItr implements ListIterator {    private Node lastReturned;//上一次next() 或者 previous()的元素    private Node next;//lastReturned->next 指向的元素    private int nextIndex;//下一个元素的位置    private int expectedModCount = modCount;}

    LinkedList从前往后遍历:

    //是否存在下一个元素public boolean hasNext() {    return nextIndex < size;}public E next() {    //检查集合的版本    checkForComodification();    if (!hasNext())        throw new NoSuchElementException();    //lastReturned赋值上次next    lastReturned = next;    //next赋值为上次next->next    next = next.next;    //下一个元素的位置    nextIndex++;    return lastReturned.item;}

    LinkedList从后往前遍历:

    //判断是否到头了public boolean hasPrevious() {    return nextIndex > 0;}//从尾部往头部取数据public E previous() {    checkForComodification();    if (!hasPrevious())        throw new NoSuchElementException();    // next==null:第一次遍历取尾节点(last),或者上一次遍历时把尾节点删除掉了    // next!=null:已经发生过遍历了,直接取前一个节点即可(next.prev)    lastReturned = next = (next == null) ? last : next.prev;    //遍历的指针-1    nextIndex--;    return lastReturned.item;}

    迭代器删除元素:

    public void remove() {    checkForComodification();    // lastReturned 是本次迭代需要删除的值    // lastReturned==null则调用者没有主动执行过 next() 或者 previos(),二直接调remove()    // lastReturned!=null,是在上次执行 next() 或者 previos()方法时赋的值    if (lastReturned == null)        throw new IllegalStateException();    //保存将当前要删除节点的下一个节点(如果是从尾往头遍历,该值永远是null)    Node lastNext = lastReturned.next;    //删除当前节点    unlink(lastReturned);     // next == lastReturned:从尾到头递归顺序,并且是第一次迭代,并且要删除最后一个元素的情况下,    // previous() 方法里面设置了 lastReturned = next = last,所以 next 和 lastReturned会相等    if (next == lastReturned)        next = lastNext;    else        nextIndex--;    lastReturned = null;    expectedModCount++;}

    感谢各位的阅读,以上就是"Java中LinkedList容器如何使用"的内容了,经过本文的学习后,相信大家对Java中LinkedList容器如何使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

    元素 节点 指针 尾部 位置 迭代 就是 指向 方法 特点 容器 复杂 复杂度 头部 时间 结构 队列 个数 从头 接口 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 华服互联网科技怎么样 互联网科技有限公司经营范围 互联网科技财经 互联网是不是新科技 北京互联网科技有限公司 为想互联网科技 以房互联网科技 左右互联网络科技 哈尔滨新华互联网科技学院 互联网科技中介 阿里互联网科技公司 南平创想时代互联网科技有限公司 威龙国际互联网科技公司 上海创道互联网络科技有限公司 半导体是互联网高科技吗 珠海东科互联网科技有限公司 互联网的科技体现在哪里 青岛易易互联网科技 10位科技互联网大佬 上海旺乐尼互联网科技有限公司 哈尔滨大商圈互联网科技有限公司 深圳九邦互联网科技有限公司 重庆互联网络科技 北京互联网络科技有限公司 金融科技与互联网金融相同和不同 互联网科技革命什么开始 坤平互联网科技 乌鲁木齐新华智原互联网科技学校 东营紫格互联网科技 科技互联网行业投资研究
    0