• LinkedList<E>源码分析


    LinkedList的数据结构就是双向链表,如下所示:

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

    构造器:

    transient int size = 0;//数据个数
    transient Node<E> first;//表示链表的第一个节点
    transient Node<E> last;//表示链表的最后一个节点
    
    public LinkedList() {
    }
    
     public LinkedList(Collection<? extends E> c) {//用于整合Collection类型的数据
            this();
            addAll(c);
    }

    add:

     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的地址,后继为null,
                                    //所以说这是一个双向链表,但不是循环的,循环的话,后继指向头节点 last
    = newNode;//让last指向新节点,也就说这个新节点是链表的最后一个元素
    if (l == null)//当第一次添加时,first,last都是null,如果last是null,表明这是一个空链表 first = newNode;//就让新节点指向first,现在first和last都是同一个节点 else l.next = newNode;//当在添加数据时,就让老链表的最后一个节点的后继指向新节点(那个节点本来是null的)
    size
    ++; //长度加1 modCount++;
    /**
    总结:
    新建一个节点,让新节点的前驱指向老链表的最后一个节点
    让老链表的最后一个节点的后继指向新节点
    让新节点变成链表的最后一个节点
    长度加1
    第一个节点前驱为null,最后一个节点后继为null

    */ }

    get:

    public E get(int index) {
            checkElementIndex(index);//检查一下索引是否在0到size的范围内
            return node(index).item;
        }
    
    Node<E> node(int index) {
            // assert isElementIndex(index);
    
            if (index < (size >> 1)) {//看看索引的位置是在链表的前半部分还是后半部分,决定正着搜索或倒着搜索,找到后返回就行啦
                Node<E> x = first;
                for (int i = 0; i < index; i++)//在这里看到链表是从0开始的
                    x = x.next;
                return x;
            } else {
                Node<E> x = last;
                for (int i = size - 1; i > index; i--)
                    x = x.prev;
                return x;
            }
        }

    remove:

     public E remove(int index) {
            checkElementIndex(index);//先检查一下索引
            return unlink(node(index));
        }
    //先拿着索引找到这个节点
    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;
        }
  • 相关阅读:
    《C++ Primer Plus》15.1 友元 学习笔记
    《C++ Primer Plus》14.4 类模板 学习笔记
    《C++ Primer Plus》14.3 多重继承 学习笔记
    《C++ Primer Plus》14.2 私有继承 学习笔记
    《C++ Primer Plus》第13章 类继承 笔记
    继承和动态内存分配——需要为继承类定义 显式析构函数、复制构造函数和赋值运算符
    C++中的抽象基类示例
    C++ 在继承中使用virtual
    《C++ Primer Plus》第12章 类和动态内存分配 学习笔记
    《C++ Primer Plus》12.7 队列模拟 学习笔记
  • 原文地址:https://www.cnblogs.com/wwzyy/p/6130442.html
Copyright © 2020-2023  润新知