LinkedList源码分析

1、成员变量

transient int size = 0;

transient Node<E> first; // 头节点

transient Node<E> last; // 尾节点

2、add()方法

/**
 * 将指定元素追加到list末尾
 */
public boolean add(E e) {
    linkLast(e);
    return true;
}

/**
 * 在指定位置插入元素
 */
public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element); // 插入到尾部
    else
        // 插入到指定位置,并将原位置的节点移动到下一个位置
        linkBefore(element, node(index));
}

/**
 * 将元素作为最后一个节点插入链表
 */
void linkLast(E e) {
    final Node<E> l = last; // 当前尾节点
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null) // 没有尾节点(list为空),将头节点也设置为newNode
        first = newNode;
    else
        l.next = newNode; // 当前尾节点的下一个节点设置为newNode
    size++;
    modCount++;
}

/**
 * 在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);
    succ.prev = newNode;
    if (pred == null) // 没有前一个节点,表示succ已经是头节点
        first = newNode;
    else
        pred.next = newNode; // succ前节点的next赋值为newNode
    size++;
    modCount++;
}

检查索引是否合法:

private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isPositionIndex(int index) {
    // 检查索引是否合法
    return index >= 0 && index <= size;
}

3、get()方法

public E get(int index) {
    // 检查索引是否合法
    checkElementIndex(index);
    return node(index).item;
}

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        // index小于size的一半,说明index在list前半部分,从头节点开始遍历
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        // index大于等于size的一半,说明index在list后半部分,从尾节点开始遍历
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

4、set()方法

public E set(int index, E element) {
    // 检查索引是否合法
    checkElementIndex(index);
    Node<E> x = node(index); // 根据index找到目标节点
    E oldVal = x.item;
    x.item = element; // 将目标节点的item替换为element
    return oldVal; // 返回原来的值
}

5、remove()方法

/**
 * 移除第一个与指定元素相等的节点
 */
public boolean remove(Object o) {
    if (o == null) { // 如果指定的节点值是null,移除list中第一个null节点
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else { // 使用equals方法找到指定节点
        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));
}

/**
 * 移除一个非空的节点 x
 */
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) { // x为头结点
        first = next;
    } else {
        prev.next = next; // x的前后节点直接相连
        x.prev = null; // 断开X与前节点的连接
    }

    if (next == null) { // x为尾结点
        last = prev;
    } else {
        next.prev = prev; // x的前后节点直接相连
        x.next = null; // 断开X与后节点的连接
    }

    x.item = null; // 清空x的数据存储
    size--;
    modCount++;
    return element;
}

未完,待续...

posted @ 2018-07-18 17:04  liycode  阅读(195)  评论(0编辑  收藏  举报