LinkedList源码分析(Java8)

LinkedList

1、特点

  • 底层是一个链式结构的集合
  • 是双向链表,当前节点都会保存前一个节点的引用和后一个节点的引用
  • 在内存空间中存储不是连续的,并且也不是循序的
  • 允许空值存在

2、 构造方法

(1)无参:

    public LinkedList() {
    }

(2)包含另一个集合:

    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

3、添加操作

(1)普通添加

    public boolean add(E e) { //添加方法的入口
        linkLast(e);
        return true;
    }
    
    void linkLast(E e) { 
        final Node<E> l = last; //获取最后一个节点的数据
        final Node<E> newNode = new Node<>(l, e, null); //定义一个新的节点数据
        last = newNode; //把新添加的这个节点作为最后一个节点
        if (l == null) // 如果当前是一个空的集合 那第一个节点也是他(第一个和最后一个是同一个数)
            first = newNode; 
        else //否则就把新的节点数赋值给原来的最后一个节点的下一个节点
            l.next = newNode;
        size++; //集合长度 +1 
        modCount++; //集合操作指令数 +1
    }

(2)特定位置添加:

    public void add(int index, E element) {
        checkPositionIndex(index); // 检查插入位置是否越界

        if (index == size) //如果是往最后一个位置插,就是普通插入
            linkLast(element);
        else //往中间插入
            linkBefore(element, node(index));
    }
    //把当前位置的数往后移,把要插入的数插入进去,(旧数的前一个节点变成了新数的前一个节点,新数的后一个节点就是旧数,旧数的前一个节点变成了新数)
    void linkBefore(E e, Node<E> succ) { //e当前要插入的数据 succ是当前位置上的数
        // assert succ != null;
        final Node<E> pred = succ.prev; //当前旧数的前一个
        final Node<E> newNode = new Node<>(pred, e, succ); //新的节点
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++; //长度 +1
        modCount++; //操作指令数 +1 
    }
    

(3)插入头位置:

    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }

(4)插入尾位置:

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

4、删除操作

(1)删除当前位置:

    public E remove(int index) { 
        checkElementIndex(index); //判断操作位置是否越界
        return unlink(node(index));
    }
    
    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item; //当前位置的值
        final Node<E> next = x.next; //当前位置的后一个值
        final Node<E> prev = x.prev; //当前位置的前一个值

        if (prev == null) { //前一个值为空说明当前位置是头位置
            first = next;  //说明你要删除的是头位置,就把他的下一个节点提上来作为头
        } else {
            prev.next = next; //就把当前位置的前一个节点的下一个节点变成当前位置的下一个节点
            x.prev = null; //当前位置的前一个节点设置为空,也就是说当前位置没有前节点了
        }

        if (next == null) { //如果后节点没有数据,说明删的是尾节点
            last = prev; //把当前位置的前节点变成尾节点
        } else {
            next.prev = prev; //当前位置后节点的前节点变成当前位置的前节点
            x.next = null;//把当前位置的后节点设置为空
        }

        x.item = null; //把当前位置的值设置为空
        size--; //长度 -1 
        modCount++; //操作指令数 +1
        return element; //返回你已经删除的节点数据
    }

(2)删除当前值:

    public boolean remove(Object o) { //通过当前值找出该值的位置,然后进行删除
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

(3)删除头:

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }
    
    private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null; 
        else
            next.prev = null; //头位置的后节点变成头位置
        size--;
        modCount++;
        return element;
    }

(4)删除尾:

    public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }
    
    private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null) //如果他没有前节点说明当前节点即是头又是尾
            first = null; //把头设置为空
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
    }

5、查找当前值

    Node<E> node(int index) {
        // assert isElementIndex(index);
        
        //用当前位置与集合的长度/2进行比较
        if (index < (size >> 1)) { //小于 则证明当前位置处于集合的前半部分
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else { //否则处于集合的后半部分
            Node<E> x = last; 
            for (int i = size - 1; i > index; i--) //然后从后往前进行遍历
                x = x.prev;
            return x;
        }
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪蓑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值