LinkedList源码基本理解。

前言

    分别总是在九月,回忆是思念的愁。深秋嫩绿的垂柳,亲吻着我额头。在那座阴雨的小城里,我从未忘记你。济南,带不走的,只有你——天桥下鸡公煲的老板娘。
    LinkedList这东西,我没用过,不过今天想看看源码,能不能发现有意思的东西呢?

——2020年09月24日

    LinkedList这东西,我天天在用,它竟然被用来作为消息队列,作为JAVA缓存使用。关于这个用法,我还是第一次见,但是在单线程的情况下是可行的。

——2020年11月24日

LinkedList

    LinkedList的底层是双端链表,大体就是下图这个样子的吧!(每个节点有pre、next属性,分别指向它的上个节点和下一个节点,并且,从理论上讲,链表可以无限长)
灵魂画师

  1.构造方法

    概述:1.无参构造器,返回一个寂寞
    2.传参数为集合的构造器,将集合转换成Object[],并遍历数组,放入链表中

无参构造方法: //返回一个寂寞
public LinkedList() {
}
带参构造方法://传入一个集合类型参数,
public LinkedList(Collection<? extends E> c) {
        this();//调用无参的寂寞
        addAll(c);//调用addAll();
}
//去看最后调用的方法
public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);//判断要添加的位置是否超过链表长度或小于0
        Object[] a = c.toArray();//将集合c转换为 Object[] 
        int numNew = a.length;//新建一个int变量 “新数字” 为 数组长度
        if (numNew == 0)//判断“新数字”是否为0,为0,则返回
            return false;
        Node<E> pred, succ; //新建两个节点,并根据新元素位置对两个节点进行赋值
        if (index == size) {//如果放在最末尾就这样赋值
            succ = null;
            pred = last;
        } else {//不是放在最末尾就这样赋值
            succ = node(index);
            pred = succ.prev;
        }
        for (Object o : a) {//遍历这个数组,调整每个节点的pre和next指针指向
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)//如果元素的pred为null,则它(newNode)为新的头结点。否则pred的next指向newNode,重新赋值pred为newNode
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }
        if (succ == null) {//遍历完了,看看一开始赋值的元素succ 为null的情况,也就是放在最末尾的情况,新的尾结点为新加的节点
            last = pred;
        } else {//否则调整新加的元素指针
            pred.next = succ;
            succ.prev = pred;
        }
        size += numNew;//长度+1
        modCount++;
        return true;
    }
    //这个构造方法还是很nb的,看的一懵逼一懵逼的,也讲不明白,自己一画图就懂了。

  2.添加元素–>add(E e)

    概述:在链表的尾部添加新的节点并调整相关指针

public boolean add(E e) {
        linkLast(e);//又调了这个方法
        return true;
}
//这个方法的意思是获取尾结点,然后把新加入的节点设置为尾结点,并调整原尾结点的next指针
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++;
}

  3.获取元素–>get(int index)

    概述:如果没有下标越界,就去遍历链表,找到结果

public E get(int index) {
        checkElementIndex(index);//看看是不是越界
        return node(index).item;//调用下面的方法
    }
    //这个方法的作用是:进行一次二分查找
    //如果index小于长度的1/2,则在从头结点开始变量,否则便从尾结点开始想前遍历,所以时间复杂度是多少?
Node<E> node(int index) {
        // assert isElementIndex(index);

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

   4.其他

    remove()方法咱就不看了哈,LinkedList 继承了 AbstractSequentialList 实现了 Deque。所以说它是一个栈,remove方法移除的是头结点。另外值得一提,这个东西不存在扩容机制,这和ArrayList是完全不同的。

总结

    LinkedList查询速度比较慢,需要从头一直遍历,时间复杂度为O(n);
    LinkedList增删比较快,只需要调整原链表中个别元素的pre和next指向,add(E) 添加到末尾时间复杂度O(1),add(index, E) 添加第几个元素后,需要先查找到第几个元素,调整指针指向操作,复杂度O(n),remove()时间复杂度为O(1);

    至此,我们基本看完了LinkedList中常用的方法了。本人水平有限,如果有不对的地方,敬请指正!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值