【源码解析】想了解LinkedList?看这篇文章就对了

积千里跬步,汇万里江河;天天进步一点点,终有一天将成大佬。java

本文基于JDK1.8node

前言

LinkedList因为实现了Deque这个接口,因此能够当队列使用。不过通常要用队列的时候推荐使用ArrayDeque,因此这里就不讲LinkedList的栈和队列功能了🌚。仍是和上篇ArrayList同样,讲些经常使用的方法。web

LinkedList内部是由双链表组成的,里面存放着一个个Node,每一个Node又包含三个元素(prev,item,next):算法

  • prev:指向前一个Node
  • item:存放存入的数据
  • next:指向下一个Node

链表的第一个Nodeprevnull,最后个Nodenextnullapp

我简单的画了一张图,能够看下源码分析

这个prev和next并非指向null,由于内存中没有为null分配空间,这边是表示是prev和next为null;post

本文内容

内部变量

相比于ArraylistLinkedList内部变量就少得多,就只有三个,size存这当前元素的个数,first指向链表的第一个,last指向列表的最后一个ui

1. 构造方法

1.1 无参构造方法

1.1.1 代码实现

List<String> list=new LinkedList<>();
复制代码

1.1.2 源码分析

无参构造只是初始化了数据,并未作任何操做(初始化 size=0 first=null last=null)this

1.2 有参构造方法

1.2.1 代码实现

List<String> oldList=new LinkedList<>();
List<String> newList=new LinkedList<>(oldList);
复制代码

1.2.2 源码分析

因为篇幅有限,addAll()方法这边就不讲了,后面另写文章再讲,里面的操做就至关于把集合里的元素复制到新集合里面。url

2. get方法

2.1 get(int index)

这里先讲get()方法,而后再讲add()方法,缘由是插入方法里用到的调用的方法个get()方法里是同样的

2.1.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.add("灰2");
list.add("灰3");
list.get(2);
复制代码

2.1.2 源码分析

  • checkElementIndex(int index)检查越界
  • node(int index)查找Node

3. add方法

3.1 add(E e)

3.1.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
复制代码

3.1.2 源码分析

  • linkLast(E e)链接最后一个元素
  • Node<E>内部类

就像开头说的,每一个Node里有三个,prev:指向前一个Nodeitem:存放存入的数据,next:指向下一个Node

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;
    }
}
复制代码

3.1.3 流程图

  • 第一次添加时的流程示意图
第一次添加时的流程示意图
第一次添加时的流程示意图
  • 不是第一次添加
不是第一次添加
不是第一次添加

3.2 add(int index, E element)

3.2.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.add(1,"hk");
复制代码

3.2.2 源码分析

这边插入元素时,先判断插入的位置是否是尾部,若是不尾部的话,先调用和get()那个同样的方法,来查找要插入位置的当前元素,而后进行插入操做

  • checkPositionIndex(int index)检查是否越界

这个检查越界的方法个get()检查越界的方法有点不一样,它是能够等于size的,由于linkedList的索引设计也是从0开始的,因此size永远比索引大1

  • linkBefore(E e, Node<E> succ)插入元素操做

3.2.3 流程图

上面说的可能有点绕,看看流程图就明白了,哈哈

  • 添加的位置为第一个
添加的位置为第一个
添加的位置为第一个
  • 添加的位置为中间
添加的位置为中间
添加的位置为中间

4. set方法

4.1 set(int index, E element)

4.1.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.set(0,"灰");
复制代码

4.1.2 源码解析

这里大多调用的是和get()里同样的方法

5. remove方法

5.1 remove(int index)

按索引删除,先找到被删除的Node,而后解除相关连接,设置Node里三大元素为null,删除后返回被删除Node里的item

5.1.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.add("灰");
list.remove(1);
复制代码

5.1.2 源码解析

  • unlink(Node<E> x)解除Node的链接,而后返回被解除连接的item

5.1.3 流程图

  • 删除的是链表里的第一个元素
删除的是链表里的第一个元素
删除的是链表里的第一个元素
  • 删除的是链表里的中间元素
  • 删除的是链表里的最后一个元素

5.2 remove(Object o)

这个删除就比较了,它内部没有用二分查找算法,而是从头开始一一对比,时间复杂度为O(n),这个删除也是只删除最先添加的数据

5.2.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.remove("hui");
复制代码

5.2.1 源码解析

unlink()方法就是上面讲的那个

6. clear方法

6.1 clear()

6.1.1 代码实现

List<String> list=new LinkedList<>();
list.add("hui");
list.clear();
复制代码

6.1.2 源码解析

总结

LinkedList里删除,添加操做通常就两个步骤,变换先后Node指向的地址,删除操做把对应Node里的三个变量都设置为null,方便GC回收。

若是要删除元素时,最好选择传入索引删除,他比直接传入要删除的对象的方法要快不少

相关文章
相关标签/搜索