zoukankan      html  css  js  c++  java
  • Java集合之LinkedList源码解析

    下面我们来看看LinkedList的底层实现,

    它继承抽象方法AbstractSequentialList<E>,实现List<E>, Deque<E>, Cloneable, java.io.Serializable接口

    它的成员属性有,

     1     transient int size = 0;
     2     transient Node<E> first;
     3     transient Node<E> last;

    size表示该集合的元素个数,初始值为0,first指向第一个Node,last指向最后一个Node,

    Node<E>是一个静态内部类,

     1 private static class Node<E> {
     2         E item;
     3         Node<E> next;
     4         Node<E> prev;
     5 
     6         Node(Node<E> prev, E element, Node<E> next) {
     7             this.item = element;
     8             this.next = next;
     9             this.prev = prev;
    10         }
    11 }

    item指当前元素,next是下一个元素的引用,prev是前一个元素的引用,

    LinkedList是一个双向链表,

    百科中对于链表的定义是

    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。

    所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

    新增元素

     假如我们有如下的代码,

    1 public static void main(String[] args) {
    2         LinkedList list  = new LinkedList<String>();
    3         list.add("ABC");
    4 }

     我们进到add(E e),

    1 public boolean add(E e) {
    2         linkLast(e);
    3         return true;
    4 }

     第2行,进到linkLast(E e),

     1 void linkLast(E e) {
     2         final Node<E> l = last;
     3         final Node<E> newNode = new Node<>(l, e, null);
     4         last = newNode;
     5         if (l == null)
     6             first = newNode;
     7         else
     8             l.next = newNode;
     9         size++;
    10         modCount++;
    11 }

    第2行,将队列的尾节点赋值给 l

    第3行,构建一个Node,

    第4行,新构建的Node追加到队尾,

    第5-8行,判断原始为节点是否为空,如果为空,当前Node是首次新增,

    第9行,size自增,

    查找元素

     假如我们有如下一段代码

    1 public static void main(String[] args) {
    2         LinkedList list  = new LinkedList<String>();
    3         list.add("ABC");
    4         list.add("DEF");
    5         
    6         list.get(0);
    7 }

     进到get(int index)方法,

    1 public E get(int index) {
    2         checkElementIndex(index);
    3         return node(index).item;
    4 }

    第2行,检验index是否是在链表内

    第3行,根据index得到node,该node的item就是要的值,下面进到node(int index)

     1 Node<E> node(int index) {
     2         // assert isElementIndex(index);
     3 
     4         if (index < (size >> 1)) {
     5             Node<E> x = first;
     6             for (int i = 0; i < index; i++)
     7                 x = x.next;
     8             return x;
     9         } else {
    10             Node<E> x = last;
    11             for (int i = size - 1; i > index; i--)
    12                 x = x.prev;
    13             return x;
    14         }
    15 }

     第4~14行,说的如果index比 size/2 小,则从前往后搜索,否则,从后往前搜索 

    插入元素

    假如我们我如下这段代码,

    1 public static void main(String[] args) {
    2         LinkedList<String> list  = new LinkedList<String>();
    3         list.add("ABC");
    4         list.add("DEF");
    5         
    6         list.add(1, "XYZ");
    7         System.out.print(list);   //[ABC, XYZ, DEF]
    8 }

     在index个元素后面,插入element,我们进到add(int index, E element),

    1 public void add(int index, E element) {
    2         checkPositionIndex(index);
    3 
    4         if (index == size)
    5             linkLast(element);
    6         else
    7             linkBefore(element, node(index));
    8 }

    第2行,index校验,必须大于等于0,且小于等于size,

    第4~7行,如果是在size个元素后插入,直接在链表尾部追加,和上面的新增方式一样,

    否则,先检索到index的元素,把待插入的元素放在node(index)之前即可,

    删除元素

    删除元素有两种,第一按照索引删除(从0开始),第二种是根据值来删除,因为LinkedList中元素可重复,在源码中从头开始遍历直到找到一个为止,

    两种方式分两步

    1.找到对应的Node<E>,

    2.调用unlink(Node<E> x)

    下面来看一下unlink(Node<E> x),

     1 E unlink(Node<E> x) {
     2         // assert x != null;
     3         final E element = x.item;
     4         final Node<E> next = x.next;
     5         final Node<E> prev = x.prev;
     6 
     7         if (prev == null) {
     8             first = next;
     9         } else {
    10             prev.next = next;
    11             x.prev = null;
    12         }
    13 
    14         if (next == null) {
    15             last = prev;
    16         } else {
    17             next.prev = prev;
    18             x.next = null;
    19         }
    20 
    21         x.item = null;
    22         size--;
    23         modCount++;
    24         return element;
    25 }

    这里我就不再逐行解释了,比较简单。

  • 相关阅读:
    Linux系统中如何查找大文件或目录文件夹的方法
    SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换
    使用纯css代码实现div的“回”字型“叠放”效果
    中国剩余定理求解“六位教授必须首次都停止上课”问题
    Java基础篇Socket网络编程中的应用实例
    计算正互反矩阵的特征值及特征向量
    维吉尼亚密码java代码实现根据密钥长度计算IC值过程
    维吉尼亚密码java完整版
    容器常用操作注意事项
    HashMap源码分析
  • 原文地址:https://www.cnblogs.com/sunshine798798/p/9075707.html
Copyright © 2011-2022 走看看