LinkedList 雙向循環鏈表和雙向鏈表的區別


從JDK1.7開始,LinkedList 由雙向循環鏈表改為雙向鏈表

首先,簡單介紹一下LinkedList:

LinkedList是List接口的雙向鏈表實現。由於是鏈表結構,所以長度沒有限制;而且添加/刪除元素的時候,只需要改變指針的指向(把鏈表斷開,插入/刪除元素,再把鏈表連起來)即可,非常方便,而ArrayList卻需要重整數組 (add/remove中間元素)。所以LinkedList適合用於添加/刪除操作頻繁的情況。

在JDK 1.7之前(此處使用JDK1.6來舉例),LinkedList是通過headerEntry實現的一個循環鏈表的。先初始化一個空的Entry,用來做header,然后首尾相連,形成一個循環鏈表:

在LinkedList中提供了兩個基本屬性size、header。

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;

 其中size表示的LinkedList的大小,header表示鏈表的表頭,Entry為節點對象。

 1 private static class Entry<E> {
 2         E element;        //元素節點
 3         Entry<E> next;    //下一個元素
 4         Entry<E> previous;  //上一個元素
 5 
 6         Entry(E element, Entry<E> next, Entry<E> previous) {
 7             this.element = element;
 8             this.next = next;
 9             this.previous = previous;
10         }
11     }

        每次添加/刪除元素都是默認在鏈尾操作。對應此處,就是在header前面操作,因為遍歷是next方向的,所以在header前面操作,就相當於在鏈表尾操作。

如下面的插入操作addBefore以及圖示,如果插入obj_3,只需要修改header.previous和obj_2.next指向obj_3即可。

 1 private Entry<E> addBefore(E e, Entry<E> entry) {
 2         //利用Entry構造函數構建一個新節點 newEntry,
 3         Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
 4         //修改newEntry的前后節點的引用,確保其鏈表的引用關系是正確的
 5         newEntry.previous.next = newEntry;
 6         newEntry.next.previous = newEntry;
 7         //容量+1
 8         size++;
 9         //修改次數+1
10         modCount++;
11         return newEntry;
12 }

 在addBefore方法中無非就是做了這件事:構建一個新節點newEntry,然后修改其前后的引用。

##########################################################################################################################################

  在JDK 1.7,1.6的headerEntry循環鏈表被替換成了first和last組成的非循環鏈表。

transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

在初始化的時候,不用去new一個Entry。

  /**
     * Constructs an empty list.
     */
    public LinkedList() {
    }

在插入/刪除的時候,也是默認在鏈尾操作。把插入的obj當成newLast,掛在oldLast的后面。另外還要先判斷first是否為空,如果為空則first = obj。

如下面的插入方法linkLast,在尾部操作,只需要把obj_3.next指向obj_4即可。

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

其中:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM