LinkedList源码解析(JDK1.8)

文档头

  • LinkedList是List和Deque接口的双向链表实现,实现所有列表操作,允许null。
  • 有关index的操作都会遍历链表,只是从头走或从尾遍历的区别
  • 是不同步,需要外部同步操作或 Collections.synchronizedList(new LinkedList(...));
  • iterator也是fast-fail类型的,iterator生成后,除了iterator自己的操作,其它对实例的结构性修改都会报ConcurrentModificationException。

变量定义

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

    LinkedList的基本数据单位,Node会记录上一个、下一个节点的引用,以及自身值。

  • transient int size = 0;

    链表长度

  •     transient Node<E> first;

    表头

  • transient Node<E> last;

    表尾

节点的插入、删除

  • linkFist(E e)  将e链到表头   
        private void linkFirst(E e) {
            final Node<E> f = first; // 获取原first
            final Node<E> newNode = new Node<>(null, e, f); // 新建节点, prev为null,新节点为 
            //头,prev指定为null,,next为原first。
            first = newNode; // 指定first为新节点
            if (f == null) // 如果原first为空,size=0,新节点就是第一个节点,尾也是新节点
                last = newNode;
            else
                f.prev = newNode; // 否则原first的prev指向新新节点
            size++;
            modCount++;
        }

     

  • linkLast(E e) 将e链到表尾 

     void linkLast(E e) {
            final Node<E> l = last; // 获取原last
            final Node<E> newNode = new Node<>(l, e, null); // 创建新node,next为null,prev为            
            // 原last
            last = newNode;
            if (l == null) // 原last为null时,原来没有元素, 这是第一个,所以first也为node。
                first = newNode;
            else
                l.next = newNode;  // 否则原last的next指向现last。
            size++;
            modCount++;
        }

     

  • linkBefore(E e, Node succ) 将e链接到succ节点前 , 要求succ节点非空   

    void linkBefore(E e, Node<E> succ) {
            // assert succ != null;
            final Node<E> pred = succ.prev;  // 获取succ前一个节点
            final Node<E> newNode = new Node<>(pred, e, succ); // 创建新节点,prev为succ前, 
            // next为succ
            succ.prev = newNode; // succ的prev指向新节点, 将succ链到新节点后。
            if (pred == null) // 如果succ原来的前一个节点为null,说明succ原来是first节点,那么
            // 现在的first就是新节点
                first = newNode;
            else // succ原来前一个不为null, 将新节点链到其后。
                pred.next = newNode;
            size++;
            modCount++;
        }

      

  • unlinkFirst、unlinkLast 分别移除first、last元素,也只是对节点的prev、next修改就可以实现,无需遍历集合
  • unlink(Node<E> e)  移除一个非空节点, 可以是头是尾 
    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) { // 如果前一个为null,说明节点原来是first,移除后的first为节点    
            // 的next
                first = next;
            } else { // 前一个不为null, 移除节点后, 前一个的next应该指向节点的next。
                prev.next = next;
                x.prev = null; 
            }
            if (next == null) { // 后一个节点为null, 节点为原来的last, 现在的last为节点的前 
            // 一个
                last = prev;
            } else { // 否则, 后一个节点的prev,指向节点的前一个。 
                next.prev = prev;
                x.next = null;
            }
            x.item = null;
            size--;
            modCount++;
            return element;
        }

     

  • node(int index) 获取index处的节点 

    Node<E> node(int index) {
            // assert isElementIndex(index);
    
            if (index < (size >> 1)) { // 如果index < (size/2)时,从头开始遍历
                Node<E> x = first;
                for (int i = 0; i < index; i++)
                    x = x.next;
                return x; 
            } else { // index > (size/2)时,从尾开始遍历。
                Node<E> x = last;
                for (int i = size - 1; i > index; i--)
                    x = x.prev;
                return x;
            }
        }

     node方法主要用作内部增删之前,找到index处的节点方便操作,最坏会遍历sise/2个元素。

public方法

public方法都是前面link、unlink、node方法的封装,前面看懂了就很容易。

  •  getFirst()、getLast()
    public E getFirst() {
            final Node<E> f = first;
            if (f == null)
                throw new NoSuchElementException();
            return f.item;
        }
     public E getLast() {
            final Node<E> l = last;
            if (l == null)
                throw new NoSuchElementException();
            return l.item;
        }

    first不为null,返回first、last值

  • removeFirst()、removeLast() 
        public E removeFirst() {
            final Node<E> f = first;
            if (f == null)
                throw new NoSuchElementException();
            return unlinkFirst(f);
        }
        public E removeLast() {
            final Node<E> l = last;
            if (l == null)
                throw new NoSuchElementException();
            return unlinkLast(l);
        }

    判断不为null,分别调用unlinkFirst、unlinkLast。

  • addFirst()、addLast() 

        public void addFirst(E e) {
            linkFirst(e);
        }
        public void addLast(E e) {
            linkLast(e);
        }

    直接调用

  • indexOf(Object o) 
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }

      IndexOf方法直接从表头开始遍历,找到第一个equals匹配的即返回。最差会遍历到表尾,也就是size个元素。

  • contains(Object o)
 public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

    contains方法调用了indexOf(int index),因此也可能遍历全表。

  •  get(int index) 、 set(int index, E element)
     public E get(int index) {
            checkElementIndex(index);
            return node(index).item;
        }
     public E set(int index, E element) {
            checkElementIndex(index);
            Node<E> x = node(index);
            E oldVal = x.item;
            x.item = element;
            return oldVal;
        }

    get、set通过node(index)查找index处元素,因此会根据index判断从头或是从尾遍历,最多遍历size/2个元素。

总结

  • LinkedList由Node构成,是双向链表结构
  • LinkedList对头、尾的增删比较高效;对链表中间对象的插入需要先遍历并找到处对象,然后执行引用的修改
  • LinkedList contains(o)、indexOf(o)会从头遍历链表,最多遍历全表; get(index)、set(index,e)时,会根据index判断从头还是从尾开始,最差遍历size/2元素。

LinkedList和ArrayList的区别

  • ArrayList是基于数组实现,通过新建数组复制元素来扩容;LinkedList是基于双向链表实现,没有容量这个概念,增删元素后直接修改size。
  • 从头插入时, LinkedList非常快,只需要新建节点然后改变原first节点的prev,,而ArrayList需要将所有元素后移,因此开销会比较大; 尾部插入时,LinkedList同理很快,,ArrayList容量足够时,只需将新节点存入数组的size位置,也挺快的。中间插入时,LinkedList需要有找到index处元素的开销,这个开销是不一定的;ArrayList需要将index处往后的元素集体移位,开销也不一定。 
  • get(index)、set(index, e)时,因为ArrayList基于数组,查找效率是常量级的;LinkedList需要找到index处元素。  这里ArrayList肯定比LinkedList快。
  • 遍历时, ArrayList支持随机快速访问,可以用for(int i; i<size;i++)循环,这样的效率非常高;LinkedList虽然也可以用fori,或者迭代器,但遍历效率不如ArrayList。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
未来社区的建设背景和需求分析指出,随着智能经济、大数据、人工智能、物联网、区块链、云计算等技术的发展,社区服务正朝着数字化、智能化转型。社区服务渠道由分散向统一融合转变,服务内容由通用庞杂向个性化、服务导向转变。未来社区将构建数字化生态,实现数据在线、组织在线、服务在线、产品智能和决策智能,赋能企业创新,同时注重人才培养和科研平台建设。 规划设计方面,未来社区将基于居民需求,打造以服务为中心的社区管理模式。通过统一的服务平台和应用,实现服务内容的整合和优化,提供灵活多样的服务方式,如推送式、订阅式、热点式等。社区将构建数据与应用的良性循环,提高服务效率,同时注重生态优美、绿色低碳、社会和谐,以实现幸福民生和产业发展。 建设运营上,未来社区强调科学规划、以人为本,创新引领、重点突破,统筹推进、整体提升。通过实施院落+社团自治工程,转变政府职能,深化社区自治法制化、信息化,解决社区治理中的重点问题。目标是培养有活力的社会组织,提高社区居民参与度和满意度,实现社区治理服务的制度机制创新。 未来社区的数字化解决方案包括信息发布系统、服务系统和管理系统。信息发布系统涵盖公共服务类和社会化服务类信息,提供政策宣传、家政服务、健康医疗咨询等功能。服务系统功能需求包括办事指南、公共服务、社区工作参与互动等,旨在提高社区服务能力。管理系统功能需求则涉及院落管理、社团管理、社工队伍管理等,以实现社区治理的现代化。 最后,未来社区建设注重整合政府、社会组织、企业等多方资源,以提高社区服务的效率和质量。通过建立社区管理服务综合信息平台,提供社区公共服务、社区社会组织管理服务和社区便民服务,实现管理精简、高效、透明,服务快速、便捷。同时,通过培育和发展社区协会、社团等组织,激发社会化组织活力,为居民提供综合性的咨询和服务,促进社区的和谐发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值