LinkedList原理

成员变量和构造方法

transient int size = 0; // 元素个数

transient Node<E> first; // 第一个节点

transient Node<E> last; // 最后一个节点

// 无参构造
public LinkedList() { 
}

// 有参构造,参数是一个 Collection
public LinkedList(Collection<? extends E> c) {
    this();  // 先用无参构造创建一个实例
    addAll(c);  // 把元素全部添加进去
}

// 每个元素是一个 Node,这是一个内部类
private static class Node<E> {
    E item; // 节点上的元素
    Node<E> next; // 上一个节点
    Node<E> prev; // 下一个节点

    // Node 构造方法
    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; // 维护尾节点
    // 如果l为空也就是链表没有节点的时候,还未初始化,维护首节点,如果不为空则不用维护首节点
    if (l == null) 
        first = newNode; 
    else 
        l.next = newNode; // 原来的尾节点下一个元素是当前节点
    size++; // 维护 size
    modCount++; // 修改次数++
}
  1. 每次元素都是添加到链表末尾
  2. 每次元素封装成一个 node 作为新的尾节点
  3. 原来的尾节点和新的尾节点互相引用形成双向链表

获取元素

  1. 获取首尾节点

    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; // 尾节点的数据
    }
    
  2. get 索引获取

    1. ArrayList 数据结构是数组,所以天然可以根据索引获取
    2. LinkedList 数据结构式链表,所以 LinkedList 是不能根据索引获取元素,但是 java 提供了根据索引获取元素的方法
    public E get(int index) {
        checkElementIndex(index); // 检查索引下标是否合法
        return node(index).item; // node(index) 是节点,item 就是节点的数据
    }
    
    // 怎么获取节点的
    Node<E> node(int index) {
        // assert isElementIndex(index);
    
        // 目标索引下标 index 在链表的前半部分还是后半部分,然后决定从前往后找还是从后往前找(避免找整个链表,只需找一半)
        if (index < (size >> 1)) { // size 右移,就是 size 的一半
            // 首节点开始,循环找下一个节点
            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;
        }
    }
    
posted @ 2023-05-24 17:06  CyrusHuang  阅读(13)  评论(0编辑  收藏  举报