对于Java集合框架的整理与理解(Linkedlist双向链表的添加与删除解析)

对Linkedlist双向链表的添加与删除的解析

首先从new一个Linkedlist开始

        LinkedList linkedList = new LinkedList<>();

走入源码:

    public LinkedList() {
    }

。。。。。看来新建一个Linkedlist什么都没有做,让我们先看看他默认的一些配置

transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

首先便是size,默认为0,接着就是默认为null的首结点和last结点。
这里看一下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;
        }
    }

可以看出,元素e,前一个结点prev,后一个结点next
标准的双向链表

接着我们进行add操作看看

  linkedList.add(1);

进入add方法的源码:

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

依然很简单,接着走入linkLast的源码
通过linkLast这个名字可以看出,Linkedlist默认采用的是尾插法插入新元素
接着我们走入linkLast方法

    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++;
    }

首先令局部变量l等于last也就是尾结点,注意,当前是第一次添加,尾结点现在是null。
然后继续创建一个新变量newNode,使用构造方法对其进行构造
newNode节点前一个节点为原last节点,后一个节点为null,e即为传入的元素
接着让last = newNode,因为用的是尾插法,所以现在最后一个结点就是刚刚新建的这个newNode结点
然后进入判断,
当什么时候,原本的最后一个last结点为空呢?
只有一个结点时,那这个结点本身是同时属于首结点和尾结点的。
只有一个结点都没有的时候,变量l才能为空,这时可以判断只有一个元素
所以将结点newNode赋值给首结点first。
注:如果目前不只有一个结点,则进入else,即将原本的尾结点的下一个结点指向当前创建的这个newNode
至此,Linkedlist的添加操作到此结束。

Linkedlist 的删除操作

其实这倒是没什么好讲的,不过既然要讲,就一起讲了。
首先依然是看源码:

    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;
    }

当传入一个object时,先进入判断
这个判断由于操作都一样,就不展开讲了
如果变量o等于null,或者o不等于null
都使用for循环,从首结点first开始遍历,
终止条件为x==null(因为双向链表的尾结点的下一个结点为null)
每次都让x=x.next,也就是一个一个结点的查询,由每个结点指向的下一个结点查询
然后就是如果查询到的值等于null(这是第一个判断
或者等于传入的变量o(第二个判断
就执行unlink也就是删除方法

    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--;
        modCount++;
        return element;
    }

这下看上去有点长,不过实际上都是些if判断占的位置
让我们开始分析
首先依然是赋值,注意,传进来的是上一个操作所查询到的结点x
然后赋值element为x的数据
next为x的下一个结点
prev为x的上一个结点
然后依然是进入判断
如果prev是空,证明啥?
没有比他更前的了,那当然就是头结点啦
那x是我们要删掉的结点
所以他的下一个结点现在开始接受组织的重任,成为首结点
如果要删除的结点不是首结点呢?
那就将它前面一个结点的后面一个结点,连接到删除结点的后面
听起来有点拗口,那就画个图把
删除前线的双箭头代表这是双向的
将它前面一个结点的后面一个结点,连接到删除结点的后面
这样操作后就变成了
在这里插入图片描述
现在第一个结点不指向要删除的结点了,而是直接指向第三个结点
同时要删除结点本身需要指向前一个结点,现在也不需要了,所以线删掉了,直接让其指向null。

接着要执行第二个判断了

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

依然是如果现在要删除的结点后面是null了
那证明这个就是尾结点嘛
那就直接把这个结点的前一个结点变成尾结点就ok了不是
否则的话就要
将下一个结点的前一个结点,连接上前一个结点
同时将本身指向下一个结点置空为null。
依然是画图来看

在这里插入图片描述这时候我们发现,这时删除这个结点就不需要考虑了
它已经被孤立了

        x.item = null;
        size--;
        modCount++;
        return element;

因此,直接将其置空
然后进行减去size的操作
就可以返回啦
这里返回的element在直接输入元素进行删除时是用不到的
只有你输入下标进行删除时,才有用
是的,Linkedlist是有下标的
当然,Linkedlist毕竟是链表而不是数组
所以他的下标其实也只是方便进行二分查找的
例如如果总长度为10
如果输入get(3)
就会进行判断,小于5,所以从首结点开始遍历
如果大于五假如是7,
那就会从尾结点进行遍历

总结

关于Linkedlist的添加与删除解析就到这了,链表的数据结构还是挺基础的知识点,
本质上也不难,如果有什么错误,欢迎提出,我会加以改正(错字咱能理解就行哈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值