LinkedList的源码阅读

1、LinkedList的基础知识

 1.1、基础概念

一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址

1.2、链表存储

基于双向链表实现

 

prev:指向前一个节点

    next:指向后一个节点

first和last分别指向链表的头节点和尾节点,当进行添加操作时,只需要将删除元素的前一个节点的next指向其后一个节点的prev,将后一个节点的prev指向前一个节点的next。

1.3、 适用场景

LinkedList适用于数据频繁添加删除操作,写多读少的情况。

1.4、与ArrayList的区别

ArrayList

LinkedList

获取指定元素

速度很快

需要从头开始查找元素

添加元素到末尾

速度很快

速度很快

在指定位置位置添加/删除

需要移动元素

不需要移动元素

内存占用

较大

2、LinkedList源代码阅读

    2.1、继承类与接口实现

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

继承

AbstractSequentiaList<E>:所以LinkedList可以实现其父类的所有方法。

实现接口

  • List接口:LinkedList是List接口的双向链表的实现
  • Deque接口:可以看作是双端队列的一种实现
  • Cloneable接口:可以实现clon()方法,对数据进行复制
  • Serializable接口:LinkedList是可序列化的

   2.2、构造方法

    LinkedList一共有两种构造方法

 public LinkedList() {
    }

  
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

LinkekList()无参的构造方法,可以初始化一个空的LinkedList

LinkedList(Collection<? extends E> c):在这个构造方法方法中调用了addAll()方法,目的是在初始化LinkedList对象时将传入的集合中的元素也添加进去

 2.3、基础方法

LinkedFirst(E e)

 private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }

在调用LinkedFirst时,会创建一个新的节点并且将新节点添加在链表的头部,过程中首先判断链表中是否有头节点(即链表是否为空);若为空,则直接将last指向新节点;不为空,则将原头节点的prev与指向新节点。

LinkedLast<E 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++;
    }

与LinkedFiest类似,在调用时,会创建一个新的节点并且将新节点添加在链表的尾部,过程中首先判断链表中是否有尾节点(即链表是否为空);若为空,则直接将first指向新节点;不为空,则将原头节点的next与指向新节点。

LinkedBeore(E e,Node<E> succ)

 void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        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++;
    }

在某个节点前添加元素,在调用LinkedBefore时,首先获取传进来的节点prev指针,并使其指向新节点,然后判断新节点的prev指针是否为空,则新节点为头节点;若不为空,则使新节点的next指针指向传进来的节点prev指针

UnLinkedFirst(Node<E> f)

 private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

调用UnLinkedList方法时,首先将头元素中的元素和next指针置为空,然后将first指向下一个节点,判断下一个节点的next指针是否为空,为空则整个链表为空,将last指向null,不为空则将下一个节点的prev指针置为空

UnLinkedLast(Node<E> l)

private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        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;
    }

与UnLinkedFirst方法类似,不过是判断需前一个节点的prev指针,为空则是空链表;不为空则将前一个节点的next指针置为空

UnLinked(Node<E> 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) {
            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;
    }

类似于添加元素,在删除时,获取删除元素的前后节点,并将前节点的next指针指向后一个节点的prev指针。

2.4核心方法

对于add(),remove(),set(),get()方法做解释

对于linkedList的方法,基本就是通过修改指针来进行方法的完成,不需要复制元素,更加高效

add()大致就是创建新的节点,然后去改变first、last、prev,next等指针即可;remove()方法类似,删除节点置空,并修改prev,next等指针,修改效率高。

   2.4.1、 add方法

  LinkedList的添加一共有6种

addFirst(E e)

  public void addFirst(E e) {
        linkFirst(e);
    }

内部调用LinkedFirst方法,在首部添加元素,参照基础方法

addLast(E e)

   public void addLast(E e) {
        linkLast(e);
    }

内部调用LinkedLast方法,在最后添加元素,参照基础方法

add(E e)

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

内部调用LinkedLast方法,在最后添加元素,参照基础方法,返回true或false

add(int index,E element)

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

根据下边添加元素,如果传入的下标等于链表长度,则在尾部添加元素,调用 LinkedLast方法;不为空则调用LinkBerore方法,将元素添加在index对应的node节点前

这里值得注意的是,链表是没有下标的,所以对应下标的位置是通过node()方法获取index的值

addAll(Collection<? extends E> c)

    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

调用另一个addAll(int index,Collection c) 方法,依次添加集合中的所有元素

         addAll(int index,Collection c)

 public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

     2.4.2、删除方法(内部调用方法在基础方法中已介绍,这里不做过多解释)

 LinkedList的删除一共有9种,与add方法区别不大,我主要对其中5中做简单介绍


        remove()

    public E remove() {
        return removeFirst();
    }

删除链表中的头元素,调用removeFirst(),在下边做介绍

remove(Object o)

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

移除列表中一个指定元素o,遍历链表,如果o不存在,则调用unlin方法删除节点,但是此时删除的时元素为null的节点,即链表不变;如果不为null,则遍历链表后,调用unlink方法删除与传入对象相等的节点。

remove(int index)

    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

 删除指定下标的节点,判断下标处的元素,并调用unlink方法

removeFirst()

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

删除头元素,定义first指针,如果没有,则抛异常,有则调用unlinkFirst方法

2.4.3 获取元素

获取元素共有三种方法,获取头元素,获取尾元素,遍历链表获取指定元素

这里与上边基本相同

get(int index)

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

通过node()方法取得index对应的节点后返回元素值

2.4.5、set方法

set(int index,E element)

    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

基本还是获取下标以及node()方法,让新的元素去替换旧的元素即可

  • 17
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值