LinkedList與ArrayList的區別

咱們都知道LinkedList和ArrayList相比:html

  一、LinkedList插入刪除相對較快,而查詢較慢;node

  二、ArrayList插入刪除相對較慢,而查詢很快(詳細可查看從源碼的角度分析List與Set的區別);數組

由類的關係可知,二者的頂層是一致的,但LinkedList額外的繼承了AbstractSequentialList類並實現了Deque接口,也就是說LinkedList擁有雙端 隊列的功能,LinkedList的實現原理與ArrayList不一樣,LinkedList是鏈表的方式實現的性能

1、LinkedList插入刪除相對較快,而查詢較慢 LinkedList的add(E e)方法實際調用的是內部的linkLast(E e)方法,也就是添加到隊列尾部this

//每一個元素在LinkedList中的存儲結構,item爲自身,prev爲上一個節點,next爲下一個節點
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;
    }
}
//添加元素
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;
    //若是原來最後一個元素爲空,則當前元素時第一個元素,給第一個元素的變量賦值
    //若是原來的最後一個元素存在,則修改該元素的下一個元素爲新的元素
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

LinkedList的add(int index,E e)方法是在某個索引前插入元素E,先根據索引index找到相應元素,在該元素前添加新元素,添加方法與linkLast相似spa

//在指定位置插入元素
public void add(int index, E element) {
 //校驗索引是否有效,主要判斷索引是否在size的範圍內
    checkPositionIndex(index);
    //若是索引正好等於size,則添加到鏈表尾部,不然在指定位置插入新元素,修改原來該位置的元素的上級節點爲新元素,新元素的上級元素爲原有元素的上級元素
    if (index == size)
        linkLast(element);
    else
        //node(index)中主要是結合index和size循環找出原有index位置的元素
        linkBefore(element, node(index));
}
//在某個節點前插入元素
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++;
}

addFirst、addLast等元素與以上實現相似,做用是添加元素到鏈表頭、鏈表尾 移除元素remove(Object o)/remove(int index0)與插入相似code

//移除元素
public boolean remove(Object o) {
    //從第一個元素開始往下循環,找到第一個匹配到的元素移除
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                //把當前元素的上個元素的next設置爲當前元素的下一個元素,把當前元素的下一個節點的prev設置爲當前元素的上一個元素,並把當前元素的prev、next、item都置爲null以便於GC
                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 E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

根據以上可知,LinkedList的添加和移除等操做只對相應位置的上下元素進行改動便可,相對於ArrayList須要進行數組的複製移位性能要好些。而在查詢來講,LinkedList須要根據索引以及內部存在的size、first、last進行循環匹配,相對於ArrayList只須要獲取數組的相應下標所對應的值就會相應慢些。htm

//根據索引獲取對象
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
//根據索引循環查詢對應的元素
Node<E> node(int index) {
    if (index < (size >> 1)) {
        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;
    }
}
相關文章
相關標籤/搜索