• JDK源码之LinkedList


    下文带/**/为源码注释//为个人注释源代码使用这个颜色

    Node对象存储元素和元素左右数据的指针
    add(e),我将我自己添加到上一个元素的Next

    addFirst(e)替换链表头
    addLast(e)替换链表尾
    addadd(index,ele)---linkLast or linkBefore

    getFirst();getLast();效率最高的两个获取
    为什么说链表获取元素慢!
    set(index,ele)更新元素同样需要遍历集合!
    removeFirst删除并重新赋值first
    removeLast删除并重新赋值Last
    remove(index)四种删除情况!
    remove(obj)删除指定元素的两种情况

    Node对象存储元素和元素左右数据的指针

    /*构建一个空列表*/

    //无参构造器

    public LinkedList() {}

    //将要添加的元素放到Node对象中的item属性中。

    //多个Node对象构成一个链表,对象中持有下一个

    //和上一个Node对象

    private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;
    Node(Node<E> prev, E element, Node<E> next) {

    //当前Node对象
    this.item = element;

    //下一个
    this.next = next;

    //上一个
    this.prev = prev;
    }
    }

    /**指向最后一个节点的指针**/

    transient Node<E> last;//LinkedList的成员变量

    /*指向第一个节点的指针*/

    transient Node<E> first;//LinkedList的成员变量

    /*该列表被修改的次数*/

    protected transient int modCount = 0;//LinkedList的成员变量

    //当前集合的元素总个数

    transient int size = 0;//LinkedList的成员变量

    add(e),我将我自己添加到上一个元素的Next

    /*将指定的元素追加到列表的末尾。*/

    //添加元素

    public boolean add(E e) {
    linkLast(e);
    return true;
    }

    /*e作为最后一个元素。*/

    void linkLast(E e) {

    //先拿到列表中最后一个元素,列表是第一次添加元素是没有的
    final Node<E> l = last;

    //创建Node对象,将最后一个元素当成Node的prev

    //传入的元素是当前Node元素,下一个不传
    final Node<E> newNode = new Node<>(l, e, null);

    //当前创建的Node成为最后一个元素,也就是下一个Node的prev
    last = newNode;

    //如果上一个为null,当链表是第一次添加元素这个是null
    if (l == null)

    //将新增的Node赋值到第一个节点的指向,现在来看这个值只会被赋值一次?
    first = newNode;
    else

    //如果last不是null则表示列表内已经有元素

    //一个新增加的元素其实是一个Node但是这个Node是没有next的

    //这个赋值代表着,如果链表内有元素,将这个新创建的Node赋值

    //给上一个Node的next
    l.next = newNode;

    size++;
    modCount++;
    }

    addFirst(e)替换链表头

    /*在列表的开头插入指定的元素。*/

    public void addFirst(E e) {
    linkFirst(e);
    }

    /*e作为第一个元素。*/

    private void linkFirst(E e) {

    //拿到first元素
    final Node<E> f = first;

    //创建新Node它的first是null,next是原来的first
    final Node<E> newNode = new Node<>(null, e, f);

    //将first指针指向新Node
    first = newNode;

    //如果f是null表示之前没有元素
    if (f == null)

    //则新添加的node同时也是last
    last = newNode;
    else//如果f不是null

    //将新添加的Node指针赋值给原有first的prev

    f.prev = newNode;

    //计数器
    size++;
    modCount++;
    }

    addLast(e)替换链表尾

    /*将指定的元素追加到列表的末尾。*/

    public void addLast(E e) {
    linkLast(e);
    }

    /*e作为最后一个元素。*/

    void linkLast(E e) {

    //拿到原来的last
    final Node<E> l = last;

    //创建新的Node它的prev是原来的last阿德next是null
    final Node<E> newNode = new Node<>(l, e, null);

    //将新创建的Node赋值给last
    last = newNode;

    //如果l==null表示原来没有元素
    if (l == null)

    //此时只有新增加的元素,所以它也是first
    first = newNode;
    else

    //如果原来有元素,则原来的last的next为新创建的Node
    l.next = newNode;

    //计数器
    size++;
    modCount++;
    }

    addadd(index,ele)---linkLast or linkBefore

    /*

    在列表的指定位置插入指定的元素。将元素当前的位置

    (如果有的话)和后续的元素向右移动(在它们的索引中添加一个)。

    */

    public void add(int index, E element) {

    //index只能大于=0或者小于=size,否则异常

    checkPositionIndex(index);

    if (index == size)

    //如果index等于size表示当前做的是追加操作
    linkLast(element);
    else

    //那这里应该是包含0的情况其实就是linkFirst()

    //不清楚为啥不判断下。

    //首先获取下标Node
    linkBefore(element, node(index));
    }

    private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /*告知参数是否是迭代器或添加操作的有效位置的索引。*/

    private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
    }

    /*将元素e插入到非空节点succ之前。*/

    void linkBefore(E e, Node<E> succ) {
    // assert succ != null;

    //拿到下标Node的prev

    final Node<E> pred = succ.prev;

    //创建新的Node它的prev是succ Node的prev,它的next是succ

    //简单描述新创建的元素在index的前边
    final Node<E> newNode = new Node<>(pred, e, succ);

    //index Node的prev指针变成了新创建的Node
    succ.prev = newNode;

    //原来的Node的prev如果是null表示它原来是第一个元素

    //那就把新创建的Node赋值到first
    if (pred == null)
    first = newNode;

    //原来的Node不是first则将原有Node的prev的next赋值成newNode
    else
    pred.next = newNode;

    //计数器
    size++;
    modCount++;
    }

    getFirst();getLast();效率最高的两个获取

    //第一个Node创建后,last和first都是Node1。第二个Node创建后last是Node2,还是firstNode1。

    //拿到Node后获取成员item。

    /*返回列表中的第一个元素。*/

    public E getFirst() {

    final Node<E> f = first;

    if (f == null)

    throw new NoSuchElementException();

    return f.item;

    }

    /*返回列表中的最后一个元素*/

    public E getLast() {

    final Node<E> l = last;

    if (l == null)

    throw new NoSuchElementException();

    return l.item;

    }

    为什么说链表获取元素慢!

    /*返回列表中指定位置的元素。*/

    public E get(int index) {

    //判断index是否合法

    checkElementIndex(index);

    //这是个重点方法。

    return node(index).item;

    }

    private void checkElementIndex(int index) {

    if (!isElementIndex(index))

     throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    }

    /**告知参数是否为现有元素的索引。**/

    private boolean isElementIndex(int index) {

    //要查询的index在0和size-1之间则返回true

    return index >= 0 && index < size;

    }

    /*返回指定元素索引处的(非空)节点。*/

    Node<E> node(int index) {

    //如果要查询的index小于当前size/2

    if (index < (size >> 1)) {
    Node<E> x = first;
    for (int i = 0; i < index; i++)
    x = x.next;
    return x;
    } else {//如果要查询的index大于当前size/2
    Node<E> x = last;
    for (int i = size - 1; i > index; i--)
    x = x.prev;
    return x;
    }
    }

    //这里假设LinkedList元素总个数为100,当前查询的index为49则100/2=50

    //49<50,先获取集合内第一个Node,然后从0开始,每次都取Node的Next

    //也就是Next代表的Node。需要循环49次才能拿到index为49的元素。

    //如果当前元素为100,当前查询的index为50,则从99开始,往后循环查询

    //需要循环48次。最快的两种情况是要查询第0号下标则第一个循环不满足直接

    //返回first或者要查询99号下标不满足第二个循环直接返回last。但是这两

    //中情况使用getFirst()或者getLast()是最快的。

    set(index,ele)更新元素同样需要遍历集合!

    /*将列表中指定位置的元素替换为指定元素。*/

    public E set(int index, E element) {

    //检验下标是否合格,上边说过这个方法。
    checkElementIndex(index);

    //同样需要找到对应的Node,上边说过这个方法。
    Node<E> x = node(index);

    //获取老的元素
    E oldVal = x.item;

    //新的元素替换老的元素
    x.item = element;

    //返回被替换的元素
    return oldVal;
    }

    removeFirst删除并重新赋值first

    /*删除并返回列表中的第一个元素。*/

    public E removeFirst() {

    //获取first元素
    final Node<E> f = first;
    if (f == null)

    //如果是null表示当前集合没有元素,抛出异常
    throw new NoSuchElementException();
    return unlinkFirst(f);
    }

    /*断开第一个非空节点的链接*/

    private E unlinkFirst(Node<E> f) {

    //获取第一个Node的item
    final E element = f.item;

    //获取第一个Node的Next
    final Node<E> next = f.next;

    //将item置为null
    f.item = null;

    //将next置为null,因为first是没有prev的,所以将

    //Node的ele元素和next全部置为null则代表可以

    //进行垃圾回收
    f.next = null; // help GC

    //第一个Node被移除后它next的理应的是first
    first = next;

    //如果被移除的Node的next现在是first是null则表示

    //当前集合没有元素则last也应当是null
    if (next == null)
    last = null;

    //如果first被移除后集合内还有元素,则新的first的prev是null
    else
    next.prev = null;

    //计数器操作

    size--;
    modCount++;

    //返回被移除的元素
    return element;
    }

    removeLast删除并重新赋值Last

    /*删除并返回列表中的最后一个元素。*/

    public E removeLast() {

    //获取最后一个Node
    final Node<E> l = last;

    //如果是null抛异常
    if (l == null)
    throw new NoSuchElementException();
    return unlinkLast(l);
    }

    /*解除最后一个非空节点l的链接。*/

    private E unlinkLast(Node<E> l) {

    //拿到last的元素
    final E element = l.item;

    //拿到last的上一个
    final Node<E> prev = l.prev;

    //断掉指针
    l.item = null;

    //断掉指针,等待被回收
    l.prev = null; // help GC

    //last被删除后它的prev理应的是新的last
    last = prev;

    //如果新的last是null,则表示集合内没有元素

    //first置为null
    if (prev == null)
    first = null;
    else

    //顺利成为last后它失去next的指针,也就是oldNext的指针
    prev.next = null;

    //计数器
    size--;
    modCount++;

    //返回被删除的元素
    return element;
    }

    remove(index)四种删除情况!

    /*

    移除此列表中指定位置的元素。将后面的元素向左移动

    (从它们的索引中减去1)。返回从列表中删除的元素。

    */

    public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
    }

    /*Unlinks non-null node x.*/

    E unlink(Node<E> x) {
    // assert x != null;

    //需要被删除Node的元素内容
    final E element = x.item;

    //需要被删除Node的下一个
    final Node<E> next = x.next;

    //需要被删除Node的上一个
    final Node<E> prev = x.prev;

    //如果上一个等于null表示被删除的元素是第一个

    if (prev == null) {

    //则需要将被删除的Node的next赋值到first
    first = next;
    } else {

    //如果被删除的Node不是第一个,需要将它的next

    prev.next = next;

    //赋值给它的prev的next。并且将它的上一个指针断掉。
    x.prev = null;
    }

    //如果被删除的Node的next是null表示它是最后一个

    if (next == null) {

    //则需要将它的prev赋值到last
    last = prev;
    } else {

    //否则表示它不是最后一个,需要将被删除的Node的prev

    //转移到下一个Node的prev
    next.prev = prev;

    //将next指针断掉
    x.next = null;
    }

    //将元素内容指针断掉

    x.item = null;

    //计数器操作
    size--;
    modCount++;
    return element;
    }

    remove(obj)删除指定元素的两种情况

    /*如果指定元素出现,则从列表中删除第一个出现的元素。如果此列表不包含该元素,则将对其进行更改。*/

    //其实这个注释是非常不令人理解的。。。我的理解是不包含该元素则不对其进行更改

    public boolean remove(Object o) {

    //如果被删除的是null
    if (o == null) {

    //从头遍历集合,根据每一个Node的item判断是不是null

    //循环结束条件是next==null

    for (Node<E> x = first; x != null; x = x.next) {

    //如果找到了就删除还是执行的unlink()最后返回true
    if (x.item == null) {
    unlink(x);
    return true;
    }
    }
    } else {

    //如果不是null照样也是从头遍历集合调用被删除元素的equals

    //这意味着如果你被删除的元素和集合内其他元素的类型不同则

    //可能会报错
    for (Node<E> x = first; x != null; x = x.next) {
    if (o.equals(x.item)) {

    //如果相同则删除并且返回true
    unlink(x);
    return true;
    }
    }
    }

    //最后没有满足条件的返回false删除失败
    return false;
    }

  • 相关阅读:
    android 网络
    java 软引用,弱引用,强引用
    android 定时, 延时 任务
    android 不失真 显示 超高清 图片 长图
    android viewHolder static 静态
    工作中怎么解决bug
    chkconfig命令
    chkconfig命令
    chkconfig命令
    linux安装 pip和setuptools
  • 原文地址:https://www.cnblogs.com/zumengjie/p/13607537.html
Copyright © 2020-2023  润新知