LinkedList详解

本文基于jdk1.7进行分析。 

LinkedList是双向链表结构,链表数据结构的特点是每个元素分配的空间不必连续、插入和删除元素时速度非常快、但访问元素的速度较慢。

LinkedList继承了AbstractSequentialList<E>,实现了List<E>, Deque<E>, Cloneable, Serializable接口。

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable

全局变量

LinkedList的全局变量有size、first和last。size用于记录当前链表的长度,first用于记录链表头部第一个节点元素的信息,last用于记录链表尾部最后一个节点元素的信息

    transient int size;
    transient LinkedList.Node<E> first;
    transient LinkedList.Node<E> last;

我们再来看看头节点LinkedList.Node内部私有类,这个Node内部私有类存储着一个节点的关键信息,item代表当前节点元素,next代表当前节点元素的下一个节点元素,prev代表当前节点元素的上一个节点元素。

    private static class Node<E> {
        //当前节点的元素
        E item;
        //下一个节点的元素
        LinkedList.Node<E> next;
        //上一个节点的元素
        LinkedList.Node<E> prev;

        //Node的构造方法
        Node(LinkedList.Node<E> var1, E var2, LinkedList.Node<E> var3) {
            this.item = var2;
            this.next = var3;
            this.prev = var1;
        }
    }

getFirst方法

获取LinkedList头节点元素

    public E getFirst() {
        //将全局变量头节点first赋值给var1
        LinkedList.Node var1 = this.first;
        //若var1为null,抛错
        if (var1 == null) {
            throw new NoSuchElementException();
        } 
        //否则返回var1的item
        else {
            return var1.item;
        }
    }

element方法

element方法内部调用getFirst方法

    public E element() {
        return this.getFirst();
    }

peek方法

peek方法是获取LinkedList头节点的方法,getFirst和element也是用来获取头节点的,但是getFirst和element如果找不到头节点会抛错,peek找不到头节点则返回null

    public E peek() {
        //var1赋值为头节点
        LinkedList.Node var1 = this.first;
        //如果头节点为null则返回null,不为null返回item
        return var1 == null ? null : var1.item;
    }

getLast方法

获取LinkedList尾节点元素

    public E getLast() {
        //将全局变量尾节点last赋值给var1
        LinkedList.Node var1 = this.last;
        //如果尾节点为null,抛错
        if (var1 == null) {
            throw new NoSuchElementException();
        }
        //返回var1的item 
        else {
            return var1.item;
        }
    }

get方法

根据下标获取LinkedList对应下标的元素

    public E get(int var1) {
        this.checkElementIndex(var1);
        return this.node(var1).item;
    }

    //检查元素下标位置是否合法
    private void checkElementIndex(int var1) {
        //若传入的元素下标超出了本LinkedList的有效范围,抛错
        if (!this.isElementIndex(var1)) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
        }
    }

    //检查传入的下标是否合法
    private boolean isElementIndex(int var1) {
        //若下标大于等于0且小于LinkedList的size,返回true
        return var1 >= 0 && var1 < this.size;
    }

    //根据下标获取LinkedList中指定下标的元素node
    LinkedList.Node<E> node(int var1) {
        LinkedList.Node var2;
        int var3;
        if (var1 < this.size >> 1) {
            var2 = this.first;

            for(var3 = 0; var3 < var1; ++var3) {
                var2 = var2.next;
            }

            return var2;
        } else {
            var2 = this.last;

            for(var3 = this.size - 1; var3 > var1; --var3) {
                var2 = var2.prev;
            }

            return var2;
        }
    }

 

removeFirst方法

移除首节点元素first

    public E removeFirst() {
        //将LinkedList首节点元素赋值给
        LinkedList.Node var1 = this.first;
        //若var1为null,抛错
        if (var1 == null) {
            throw new NoSuchElementException();
        }
        //否则开始移除首节点 
        else {
            return this.unlinkFirst(var1);
        }
    }

    //移除首节点
    private E unlinkFirst(LinkedList.Node<E> var1) {
        //将首节点var1的当前元素item赋值给var2
        Object var2 = var1.item;
        //用var3存储首节点var1的下一个节点元素
        LinkedList.Node var3 = var1.next;

        //将首节点的当前元素item赋值为null
        var1.item = null;
        //将首节点的下一个节点元素next赋值为null
        var1.next = null;
        //将首节点赋值为var3
        this.first = var3;
        //若var3为null,则给尾节点赋值为null
        if (var3 == null) {
            this.last = null;
        }
        //这里var1作为首节点已经被移除了,所以var1的下一节点var3的前一节应该赋值为null 
        else {
            var3.prev = null;
        }

        //size减一
        --this.size;
        ++this.modCount;
        //返回被移除的元素
        return var2;
    }

removeLast

移除尾节点元素last

    public E removeLast() {
        //将LinkedList的尾节点赋值给var1
        LinkedList.Node var1 = this.last;
        //若尾节点为null,抛错
        if (var1 == null) {
            throw new NoSuchElementException();
        }
        //不为null则移除尾节点 
        else {
            return this.unlinkLast(var1);
        }
    }

    private E unlinkLast(LinkedList.Node<E> var1) {
        //将尾节点var1的当前元素赋值给var2
        Object var2 = var1.item;
        //将尾节点的前一节点赋值给var3
        LinkedList.Node var3 = var1.prev;
        //将尾节点var1的item赋值为null
        var1.item = null;
        //将尾节点var1的上一节点元素赋值为null
        var1.prev = null;
        //将尾节点赋值为var3
        this.last = var3;
        //如果前一节点为null
        if (var3 == null) {
            //将首节点赋值为null
            this.first = null;
        } else {
            //将前一节点var3的下一节点赋值为null
            var3.next = null;
        }

        //size-1
        --this.size;
        ++this.modCount;
        //返回被移除的var2元素
        return var2;
    }

addFirst方法

添加首节点

    public void addFirst(E var1) {
        this.linkFirst(var1);
    }

    private void linkFirst(E var1) {
        //用var2来存储当前的首节点
        LinkedList.Node var2 = this.first;
        //新建var3首节点元素,其前节点为null(这里因为首节点的前一节点肯定为null),后节点为var2,当前节点为传入的var1
        LinkedList.Node var3 = new LinkedList.Node((LinkedList.Node)null, var1, var2);
        //将新建的var3首节点元素赋值给this.first
        this.first = var3;
        //如果之前的首节点为null,那么新建的var3元素既是首节点也是尾节点
        if (var2 == null) {
            //将LinkedList尾节点赋值为var3
            this.last = var3;
        } else {
            //var2不为null的话,则var3就是var2的前一节点
            var2.prev = var3;
        }
        //size+1
        ++this.size;
        ++this.modCount;
    }

addLast方法

addLast方法,将新元素节点增加到链表最后作为链表的尾节点

    public void addLast(E var1) {
        this.linkLast(var1);
    }

    void linkLast(E var1) {
        //将尾节点赋值给var2
        LinkedList.Node var2 = this.last;
        //新建一个以var1为item的node节点对象var3
        LinkedList.Node var3 = new LinkedList.Node(var2, var1, (LinkedList.Node)null);
        //将新建的var3节点赋值给尾节点last
        this.last = var3;
        
        if (var2 == null) {
            //若原来的尾节点var2为null,则代表这个LinkedList一开始就没有节点,所以新建的尾节点也就是头节点
            this.first = var3;
        } else {
            //否则var2的下一节点就是var3
            var2.next = var3;
        }
        //容量+1
        ++this.size;
        ++this.modCount;
    }

contains和indexOf方法

contains方法通过调用indexOf方法判断元素所在位置下标是否为-1来判断元素是否存在

    public boolean contains(Object var1) {
        return this.indexOf(var1) != -1;
    }

    public int indexOf(Object var1) {
        int var2 = 0;
        LinkedList.Node var3;
        //若传入的元素var1为null
        if (var1 == null) {
            //以首节点开始,只要下一节点不为null,就一直循环
            for(var3 = this.first; var3 != null; var3 = var3.next) {
                //如果当前节点为null,返回其下标var2
                if (var3.item == null) {
                    return var2;
                }
                //下标+1
                ++var2;
            }
        }
        //若传入的var1不为null 
        else {
            //以首节点开始,只要下一节点不为null,就一直循环
            for(var3 = this.first; var3 != null; var3 = var3.next) {
                //比对var1和var3,找到后直接返回其下标
                if (var1.equals(var3.item)) {
                    return var2;
                }
                //下标+1
                ++var2;
            }
        }

        return -1;
    }

size方法

返回LinkList的长度

    public int size() {
        return this.size;
    }

add方法

这里的add方法和上面的addLast实现原理是一样的,只不过多返回了一个true

    public boolean add(E var1) {
        this.linkLast(var1);
        return true;
    }

    void linkLast(E var1) {
        //将尾节点赋值给var2
        LinkedList.Node var2 = this.last;
        //新建一个以var1为item的node节点对象var3
        LinkedList.Node var3 = new LinkedList.Node(var2, var1, (LinkedList.Node)null);
        //将新建的var3节点赋值给尾节点last
        this.last = var3;
        
        if (var2 == null) {
            //若原来的尾节点var2为null,则代表这个LinkedList一开始就没有节点,所以新建的尾节点也就是头节点
            this.first = var3;
        } else {
            //否则var2的下一节点就是var3
            var2.next = var3;
        }
        //容量+1
        ++this.size;
        ++this.modCount;
    }

add重载方法

在指定下标设置添加元素

    public void add(int var1, E var2) {
        //检查下标位置是否合法
        this.checkPositionIndex(var1);
        //如果传入var1等于当前容量大小
        if (var1 == this.size) {    
            //则直接将传入的元素存入链表的最后
            this.linkLast(var2);
        } else {
            //否则就往前面加
            this.linkBefore(var2, this.node(var1));
        }

    }

    void linkLast(E var1) {
        //将尾节点赋值给var2
        LinkedList.Node var2 = this.last;
        //新建一个以var1为item的node节点对象var3
        LinkedList.Node var3 = new LinkedList.Node(var2, var1, (LinkedList.Node)null);
        //将新建的var3节点赋值给尾节点last
        this.last = var3;
        
        if (var2 == null) {
            //若原来的尾节点var2为null,则代表这个LinkedList一开始就没有节点,所以新建的尾节点也就是头节点
            this.first = var3;
        } else {
            //否则var2的下一节点就是var3
            var2.next = var3;
        }
        //容量+1
        ++this.size;
        ++this.modCount;
    }

    void linkBefore(E var1, LinkedList.Node<E> var2) {
        //用var3暂存原节点的前一节点
        LinkedList.Node var3 = var2.prev;
        //新建var4节点对象,用var1作为item,var3作为前一节点,var2作为后一节点
        LinkedList.Node var4 = new LinkedList.Node(var3, var1, var2);
        //将var2的前一节点赋值为新对象var4
        var2.prev = var4;
        //如果var3为Null,
        if (var3 == null) {
            //则var4就是头节点
            this.first = var4;
        } else {
            //否则给var3的下一节点赋值为var4
            var3.next = var4;
        }

        //容量+1
        ++this.size;
        ++this.modCount;
    }

set方法

在指定下标位置设置元素

    public E set(int var1, E var2) {
        //先检查下标是否合法
        this.checkElementIndex(var1);
        //根据传入的下标查询对应的节点元素
        LinkedList.Node var3 = this.node(var1);
        //用var4暂存查到的原节点元素的item
        Object var4 = var3.item;
        //将var1下标对应的元素item替换成传入的元素
        var3.item = var2;
        //最后返回被替换的元素
        return var4;
    }

    //检查元素下标位置是否合法
    private void checkElementIndex(int var1) {
        //若传入的元素下标超出了本LinkedList的有效范围,抛错
        if (!this.isElementIndex(var1)) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
        }
    }

    //检查传入的下标是否合法
    private boolean isElementIndex(int var1) {
        //若下标大于等于0且小于LinkedList的size,返回true
        return var1 >= 0 && var1 < this.size;
    }

    //根据下标获取LinkedList中指定下标的元素node
    LinkedList.Node<E> node(int var1) {
        LinkedList.Node var2;
        int var3;
        if (var1 < this.size >> 1) {
            var2 = this.first;

            for(var3 = 0; var3 < var1; ++var3) {
                var2 = var2.next;
            }

            return var2;
        } else {
            var2 = this.last;

            for(var3 = this.size - 1; var3 > var1; --var3) {
                var2 = var2.prev;
            }

            return var2;
        }
    }

remove方法

    
    public boolean remove(Object var1) {
        LinkedList.Node var2;
        //如果传入的var1为null
        if (var1 == null) {
            //以头节点开始,只要下一节点不为Null,就一直循环
            for(var2 = this.first; var2 != null; var2 = var2.next) {
                //找到item为null的节点后开始移除这个节点
                if (var2.item == null) {
                    this.unlink(var2);
                    return true;
                }
            }
        }
        //如果传入的var1不为null 
        else {
            //以头节点开始,只要下一节点不为Null,就一直循环
            for(var2 = this.first; var2 != null; var2 = var2.next) {
                //直到找到var1对应的节点,开始移除
                if (var1.equals(var2.item)) {
                    this.unlink(var2);
                    return true;
                }
            }
        }

        return false;
    }

    //解除链接的方法
    E unlink(LinkedList.Node<E> var1) {
        //用var2暂存要被移除的节点var1.item
        Object var2 = var1.item;
        //用var3存储var1的下一节点
        LinkedList.Node var3 = var1.next;
        //用var4存储var1的上一节点
        LinkedList.Node var4 = var1.prev;
        //如果var4为null,又因为var1要被移除,所以本LinkedList的首节点直接赋值为var3
        if (var4 == null) {
            this.first = var3;
        }
        //否则var4的下一节点赋值为var3,var1的上一节点赋值为null
        else {
            var4.next = var3;
            var1.prev = null;
        }

        //如果var3为null,又因为var1要被移除,所以var4既是首节点也是尾节点
        if (var3 == null) {
            this.last = var4;
        }
        //如果var3不为Null,则var3的前一个节点是var4,var1的下一节点为null
        else {
            var3.prev = var4;
            var1.next = null;
        }
        
        //var1的item赋值为null
        var1.item = null;
        //size-1
        --this.size;
        ++this.modCount;
        //返回被移除的节点var2
        return var2;
    }

remove方法

remove重载方法,内部调用removeFirst方法,移除头节点

    public E remove() {
        return this.removeFirst();
    }

poll方法

poll方法内部调用unlinkFirst方法来移除头节点,remove和removeFirst找不到头节点时会抛错,而poll找不到头节点只会返回null

    public E poll() {
        LinkedList.Node var1 = this.first;
        return var1 == null ? null : this.unlinkFirst(var1);
    }

addAll方法

研读源码的时候发现里面的变量大多是var1,var2,var3,不便于理解,我自己修改了下变量名

    public boolean addAll(Collection<? extends E> collection) {
        //内部调用addAll重载方法
        return this.addAll(this.size, collection);
    }

    //变量名太low,TODO
    public boolean addAll(int size, Collection<? extends E> collection) {
        //检查size是否在规定范围之内
        this.checkPositionIndex(size);
        //将Collection类型collection转化为Array类型
        Object[] tempArr = collection.toArray();
        //用tempArrLen存储tempArr 的长度
        int tempArrLen= tempArr.length;
        //如果长度为0,直接返回false
        if (tempArrLen == 0) {
            return false;
        } 
        else {
            LinkedList.Node var5;
            LinkedList.Node var6;
            //
            if (size == this.size) {
                var6 = null;
                var5 = this.last;
            } else {
                var6 = this.node(size);
                var5 = var6.prev;
            }

            Object[] var7 = tempArr;
            int var8 = var3.length;

            for(int i = 0; i < var8; ++i) {
                Object var10 = var7[i];
                LinkedList.Node var12 = new LinkedList.Node(var5, var10, (LinkedList.Node)null);
                if (var5 == null) {
                    this.first = var12;
                } else {
                    var5.next = var12;
                }

                var5 = var12;
            }

            if (var6 == null) {
                this.last = var5;
            } else {
                var5.next = var6;
                var6.prev = var5;
            }

            this.size += tempArrLen;
            ++this.modCount;
            return true;
        }
    }
    
    //检查下标是否在规定范围之内
    private void checkPositionIndex(int size) {
        //如果size不在范围之内,抛错
        if (!this.isPositionIndex(size)) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(size));
        }
    }

    //判断位置下标是否在范围之内
    private boolean isPositionIndex(int size) {
        return size>= 0 && size <= this.size;
    }

    
    LinkedList.Node<E> node(int var1) {
        LinkedList.Node var2;
        int var3;
        if (var1 < this.size >> 1) {
            var2 = this.first;

            for(var3 = 0; var3 < var1; ++var3) {
                var2 = var2.next;
            }

            return var2;
        } else {
            var2 = this.last;

            for(var3 = this.size - 1; var3 > var1; --var3) {
                var2 = var2.prev;
            }

            return var2;
        }
    }

clear方法

LinkedList清空方法

    public void clear() {
        //新建临时变量var
        LinkedList.Node var2;
        //从LinkedList的头节点开始循环,逐个将所有节点的item、next、prev属性赋值为null
        for(LinkedList.Node var1 = this.first; var1 != null; var1 = var2) {
            var2 = var1.next;
            var1.item = null;
            var1.next = null;
            var1.prev = null;
        }
        
        //再将LinkedList的头节点和尾节点赋值为null
        this.first = this.last = null;
        //size设置为0
        this.size = 0;
        ++this.modCount;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值