• LinkedList与ArrayList的区别


    我们都知道LinkedList和ArrayList相比:

      1、LinkedList插入删除相对较快,而查询较慢;

      2、ArrayList插入删除相对较慢,而查询很快(详细可查看从源码的角度分析List与Set的区别);

    由类的关系可知,两者的顶层是一致的,但LinkedList额外的继承了AbstractSequentialList类并实现了Deque接口,也就是说LinkedList拥有双端 队列的功能,LinkedList的实现原理与ArrayList不同,LinkedList是链表的方式实现的

    一、LinkedList插入删除相对较快,而查询较慢 LinkedList的add(E e)方法实际调用的是内部的linkLast(E e)方法,也就是添加到队列尾部

    //每个元素在LinkedList中的存储结构,item为自身,prev为上一个节点,next为下一个节点
    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;
        }
    }
    //添加元素
    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++;
        modCount++;
    }

    LinkedList的add(int index,E e)方法是在某个索引前插入元素E,先根据索引index找到相应元素,在该元素前添加新元素,添加方法与linkLast类似

    //在指定位置插入元素
    public void add(int index, E element) {
     //校验索引是否有效,主要判断索引是否在size的范围内
        checkPositionIndex(index);
        //如果索引正好等于size,则添加到链表尾部,否则在指定位置插入新元素,修改原来该位置的元素的上级节点为新元素,新元素的上级元素为原有元素的上级元素
        if (index == size)
            linkLast(element);
        else
            //node(index)中主要是结合index和size循环找出原有index位置的元素
            linkBefore(element, node(index));
    }
    //在某个节点前插入元素
    void linkBefore(E e, Node<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++;
        modCount++;
    }

    addFirst、addLast等元素与以上实现类似,作用是添加元素到链表头、链表尾 移除元素remove(Object o)/remove(int index0)与插入类似

    //移除元素
    public boolean remove(Object o) {
        //从第一个元素开始往下循环,找到第一个匹配到的元素移除
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    //把当前元素的上个元素的next设置为当前元素的下一个元素,把当前元素的下一个节点的prev设置为当前元素的上一个元素,并把当前元素的prev、next、item都置为null以便于GC
                    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;
    }
    //根据索引移除元素,先根据索引找出当前元素再进行移除
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    根据以上可知,LinkedList的添加和移除等操作只对相应位置的上下元素进行改动即可,相对于ArrayList需要进行数组的复制移位性能要好些。而在查询来说,LinkedList需要根据索引以及内部存在的size、first、last进行循环匹配,相对于ArrayList只需要获取数组的相应下标所对应的值就会相应慢些。

    //根据索引获取对象
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    //根据索引循环查询对应的元素
    Node<E> node(int 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;
        }
    }
    一步一步往前走,总有一天到达目标... 内容仅供参考,如有错漏,烦请指出,不胜感激!
  • 相关阅读:
    Java开源内容管理CMS系统J4CMS支持静态化直接ftp上传到你的空间了
    JAVA数组的定义及用法
    从本地上传整个目录到hdfs的java程序
    图片轮显效果大全
    Windows 自己主动关机命令 shuntdown
    Android源码是这样搞到的(图解)
    JSONObject与JSONArray的使用
    教你用笔记本破解无线路由器password
    tomcat配置文件server.xml具体解释
    SQLite的SQL语法
  • 原文地址:https://www.cnblogs.com/begin2016/p/9704103.html
Copyright © 2020-2023  润新知