zoukankan      html  css  js  c++  java
  • LinkedList的源码分析(基于jdk1.8)

    1.初始化

    public LinkedList() {
    }

    并未开辟任何类似于数组一样的存储空间,那么链表是如何存储元素的呢?

    2.Node类型

    存储到链表中的元素会被封装为一个Node类型的结点。并且链表只需记录第一个结点的位置和最后一个结点的位置。然后每一个结点,前后连接,就可以串起来变成一整个链表。

    transient Node<E> first;//指向链表的第一个结点
    
    transient Node<E> last;//指向链表的最后一个结点
       
    //LinkedList中有一个内部类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; } }

    3.添加元素

    public boolean add(E e) {
        //默认链接到链表末尾
        linkLast(e);
        return true;
    }
    void linkLast(E e) {
        //用l记录当前链表的最后一个结点对象
        final Node<E> l = last;
    
        //创建一个新结点对象,并且指定当前新结点的前一个结点为l
        final Node<E> newNode = new Node<>(l, e, null);
    
        //当前新结点就变成了链表的最后一个结点
        last = newNode;
    
        if (l == null)
          //如果当前链表是空的,那么新结点对象,同时也是链表的第一个结点
            first = newNode;
        else
            //如果当前链表不是空的,那么最后一个结点的next就指向当前新结点
            l.next = newNode;
    
       //元素个数增加
        size++;
    
       //修改次数增加
        modCount++;
    }

     

    4.删除元素

    public boolean remove(Object o) {
       //分o是否是null讨论,从头到尾找到要删除的元素o对应的Node结点对象,然后删除
        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;
    }
    E unlink(Node
    <E> x) { final E element = x.item; //用next记录被删除结点的后一个结点 final Node<E> next = x.next; //用prev记录被删除结点的前一个结点 final Node<E> prev = x.prev; if (prev == null) { //如果删除的是第一个结点,那么被删除的结点的后一个结点将成为第一个结点 first = next; } else { //否则被删除结点的前一个结点的next应该指向被删除结点的后一个结点 prev.next = next; //断开被删除结点与前一个结点的关系 x.prev = null; } if (next == null) { //如果删除的是最后一个结点,那么被删除结点的前一个结点将变成最后一个结点 last = prev; } else { //否则被删除结点的后一个结点的prev应该指向被删除结点的额前一个结点 next.prev = prev; //断开被删除结点与后一个结点的关系 x.next = null; } //彻底把被删除结点变成垃圾对象 x.item = null; //元素个数减少 size--; //修改次数增加 modCount++; return element; }

     5.指定位置插入元素

    public void add(int index, E element) {
        //检查索引位置的合理性
        checkPositionIndex(index);
    
        if (index == size)
            //如果位置是在最后,那么链接到链表的最后
            linkLast(element);
        else
            //否则在链表中间插入
            //node(index)表示找到index位置的Node对象
            linkBefore(element, node(index));
    }
    void linkBefore(E e, Node<E> succ) { // pred记录被插入位置的前一个结点 final Node<E> pred = succ.prev; //构建一个新结点 final Node<E> newNode = new Node<>(pred, e, succ); //把新结点插入到succ的前面 succ.prev = newNode; //如果被插入点是链表的开头,那么新结点变成了链表头 if (pred == null) first = newNode; else //否则pred的next就变成了新结点 pred.next = newNode;
    //元素个数增加 size++; //修改次数增加 modCount++; }

     6.总结

    对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高。因为不涉及到移动元素,只需要修改前后结点的关系。也不需要涉及到扩容

    此类虽然提供按照索引查找与操作的方法,但是效率不高,如果需要按索引操作,那么建议使用动态数组

  • 相关阅读:
    html 的一些基础操作
    java 通过反射调用属性,方法,构造器
    java 通过反射获取类属性结构,类方法,类父类及其泛型,类,接口和包
    java 反射,类的加载过程以及Classloader类加载器
    java 随机读写访问流及seek方法
    java 序列化机制
    java 标准输入输出流,打印流,数据流
    hp400 硒鼓加粉图解
    Delphi XE5 android 获取网络状态
    Delphi XE5 常见问题解答
  • 原文地址:https://www.cnblogs.com/duoduotouhenying/p/10136441.html
Copyright © 2011-2022 走看看