【Java面試】LinkedList和ArrayList的異同點

我們先把LinkedList的增刪改查源碼都閱讀一遍,然後再各個方面進行比較兩者之間的區別。

LinkedList linkedList = new LinkedList();
// add
linkedList.add("1");
// get
linkedList.get(0);
// set
linkedList.set(0, "1");
// remove
linkedList.remove("1");

ArrayList是對象數組,LinkedList是鏈表

先從新增開始,他的步驟也十分的簡單,和ArrayList完全不同的是,一看他的數據結構,屬性中包含next多半是鏈表的結構,但是具體是什麼鏈表,我們還要繼續看他的其他方法。

/**
 * Links e as last element.
 */
void linkLast(E e) {
    // 最後一個元素賦值給l
    final LinkedList.Node<E> l = last;
    // 新建一個節點賦值給newNode
    // 下一個節點爲空
    // item爲設置的節點
    // 最後一個節點賦值給上一個節點
    final LinkedList.Node<E> newNode = new LinkedList.Node<>(l, e, null);
    // 當前新建的節點賦值爲最後一個節
    last = newNode;
    // 最後一個節點爲空
    // 也就是第一個節點被設置的時候
    if (l == null)
        // 設置最新的節點爲第一個節點
        first = newNode;
    else
        // 新增前的最後一個節點的next屬性爲當前新增節點
        l.next = newNode;
    // 長度自增
    size++;
    modCount++;
}

LinkedList是雙向鏈表

我們再看看他內部的Node對象有哪些屬性。

Node(LinkedList.Node<E> prev, E element, LinkedList.Node<E> next) {
	// 當前節點
    this.item = element;
    // 下一個節點
    this.next = next;
    // 上一個節點
    this.prev = prev;
}

然後繼續看他的取數邏輯是怎樣的,一會兒從前面第一個節點開始,一會兒從最後一個節點開始取數。

/**
 * Returns the (non-null) Node at the specified element index.
 */
LinkedList.Node<E> node(int index) {
    // assert isElementIndex(index);

    // 下標 小於 長度除以2
    if (index < (size >> 1)) {
        // 第一個節點賦值給x
        LinkedList.Node<E> x = first;
        // 正向遍歷到下標節點爲止
        for (int i = 0; i < index; i++)
            // x的下一個元素賦值給x
            x = x.next;
        // 返回到下標爲止的x對象
        return x;
    } else {// 下標 大於等於 長度除以2
        // 最後一個節點賦值給x
        LinkedList.Node<E> x = last;
        // 反向遍歷對象
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

一開始我對這個邏輯很費解,但是後來思考了一下,他是一個鏈表的結構,並且存儲了第一個節點和最後一個節點作爲遍歷的開始節點,也就是雙鏈表的結構。這裏的index < (size >> 1)是爲了判斷從哪裏開始遍歷這個鏈表才能讓,也就是我們常用的二分法,從而降低複雜度從而加快查詢的速度。

再看看改的邏輯是什麼,基本和取數的邏輯相似,只是做了item屬性的替換而已。

/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
   checkElementIndex(index);
   // 和get邏輯類似
   Node<E> x = node(index);
   E oldVal = x.item;
   // 匹配到就修改他內部的item屬性
   x.item = element;
   return oldVal;
}

刪除的邏輯我最後定位都了unlink方法。

/**
 * Unlinks non-null node x.
 */
E unlink(LinkedList.Node<E> x) {
    // assert x != null;
    // x的值賦值個體element
    final E element = x.item;
    // x的下一個節點賦值給next
    final LinkedList.Node<E> next = x.next;
    // x的上一個節點賦值給prev
    final LinkedList.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;
}

這個也很好理解,我們畫個圖理解一下。LinkedList刪除開頭末尾
LinkedList中間刪除
他和ArrayList相同點是,他們都不是真正意義上的刪除,被“刪除”的空間還是被繼續佔用,前者是前後節點通知內容的替換,而後者則是本身數組的替換。


參考資料

總結

  • LinkedList是鏈表結構,ArrayList是對象數組。
  • LinkedList是雙鏈表結構。
  • LinkedList和ArrayLsit都不是實際意義上的刪除。

文章中出現的任何錯誤歡迎指正,共同進步!

最後做個小小廣告,有對WEB開發和網絡安全感興趣的,可以加羣一起學習和交流!

交流羣
QQ:425343603

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章