• 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)
    没有下标,不能随机访问,访问除了首尾元素外比较低效

  • 相关阅读:
    10 行 Python 代码,批量压缩图片 500 张,简直太强大了
    听说苏州是互联网的荒漠,真的吗?
    sum() 函数性能堪忧,列表降维有何良方?
    len(x) 击败 x.len(),从内置函数看 Python 的设计思想
    如何给列表降维?sum()函数的妙用
    Shell脚本关于循环的一些总结
    大技霸教你远程执行Linux脚本和命令
    老板对我说,你要是能找出公司里摸鱼的人,我就给你涨薪!于是我写了两个脚本……
    Linux 命令行下搜索工具大盘点,效率提高不止一倍!
    饿了么总监分享:我是如何完成从程序员到管理层的蜕变?
  • 原文地址:https://www.cnblogs.com/paper-man/p/13284629.html
Copyright © 2020-2023  润新知