LinkedList源码分析

简介

List、Deque接口的双链列表实现。实现所有可选的列表操作,并允许null元素。
此实现非线程安全,如果多个线程同时访问链表,并且至少一个线程在结构上修改了链表,则它必须从外部同步。
可以这样构造同步集合:Collections.synchronizedList(new LinkedList(…))
所谓结构上修改链表,就是会影响链表长度的操作,比如添加,删除,像set修改就不会影响结构。
迭代器支持快速失败,而不是在将来的不确定时间内冒着不确定的行为风险。

类继承关系

在这里插入图片描述
Serializable 标志可被序列化
Cloneable 标志能被复制
实现Deque(双端队列)接口 能够在头和尾操作元素
继承AbstractSequentialList类 提供了顺序访问的基本实现

属性

transient int size = 0;	//元素个数
transient Node<E> first;	//指向第一个节点的指针
transient Node<E> last;	//指向最后一个节点的指针

构造方法

//构造一个空集合
public LinkedList() {
}
//构造一个包含指定数据的集合
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

内部类

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

private class ListItr implements ListIterator<E> {
 	......	//实现了hasnext next hasPrevious previous等迭代器方法   
}

主要方法

// 将元素e作为第一个节点
// 这里指针操作值得仔细品味
private void linkFirst(E e) {
    final Node<E> f = first; //f指向第一个节点
    final Node<E> newNode = new Node<>(null, e, f);//构造节点
    first = newNode;//first指针指向新构造节点 注意:此时f仍然指向原来的第一个节点
    //如果原来的节点为空 说明集合为空 随即将尾节点指向新构造节点
    //否则就将原来的头节点前驱指向新节点
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;//容量加一
    modCount++;//修改次数加一
}
//将元素e作为最后的节点
void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}
// 将元素e插入非空节点succ前面
void linkBefore(E e, Node<E> succ) {
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}
//移除非空的第一个节点f
private E unlinkFirst(Node<E> f) {
	//取出来当前元素和下一个节点
    final E element = f.item;
    final Node<E> next = f.next;
    //将当前元素的指针置空 以使gc回收
    f.item = null;
    f.next = null; // help GC
    first = next; //first指向下一个节点
    //如果下一个节点为空 说明集合原本就一个元素 随即将尾节点置空
    //否则将下一个节点(也即是将来的手节点)的前驱置空
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}
//取消链接非空的最后一个节点l
private E unlinkLast(Node<E> l) {
    final E element = l.item;
    final Node<E> prev = l.prev;
    l.item = null;
    l.prev = null; // help GC
    last = prev;
    if (prev == null)
        first = null;
    else
        prev.next = null;
    size--;
    modCount++;
    return element;
}
// 取消链接非空节点x
E unlink(Node<E> x) {
    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;
}

删除

// 循环找到第一个元素删除
public boolean remove(Object o) {
    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;
}
//循环将每个节点的元素置空
public void clear() {
	//先清除中间元素
    for (Node<E> x = first; x != null; ) {
        Node<E> next = x.next;
        x.item = null;
        x.next = null;
        x.prev = null;
        x = next;
    }
    first = last = null;//首尾节点清空
    size = 0;//容量置零
    modCount++;
}

查找元素

//循环比对找到第一个相同的元素位置
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;
}

栈操作

//
//入栈
public void push(E e) {
    addFirst(e);
}
//出栈
public E pop() {
    return removeFirst();
}
// 还有很多其他队列操作

总结

LinkedList是一个双向链表,还是一个双端队列,队列,栈
在首尾插入删除效率高,复杂度O(1)
在链表中间删除查找效率低,平均复杂度O(n)
没有下标,不能随机访问,访问除了首尾元素外比较低效

posted @ 2019-10-22 11:50  慢慢行  阅读(14)  评论(0编辑  收藏  举报