資料結構之「連結串列」

清塵閒聊發表於2019-03-19

什麼是連結串列?

連結串列是一種線性表,但並不會按線性的順序儲存資料,而是在每一個節點裡存到下一個節點的指標(Pointer)。因此它不需要分配連續的儲存空間,也不需要預先固定元素的大小,它可以動態的新增刪除元素,而且時間複雜度是O(1)。只不過查詢某個元素時,時間複雜度是O(n)。 連結串列有多種不同的型別:單向連結串列,雙向連結串列和迴圈連結串列。

單向連結串列

單向連結串列是最簡單的一種,它包含兩個域,一個資訊域和一個指標域。這個連結指向列表中的下一個節點,而最後一個節點則指向一個空值。

單向連結串列

雙向連結串列

雙向連結串列中不僅有指向後一個節點的指標,還有指向前一個節點的指標。這樣可以從任何一個節點訪問前一個節點,當然也可以訪問後一個節點。

雙向連結串列

迴圈連結串列

迴圈連結串列是把連結串列的首節點和末節點連線在一起,形成一個環。這種方式在單向和雙向連結串列中皆可實現。

迴圈連結串列

連結串列有什麼作用?

根據連結串列的特性,動態的把元素加入到連結串列中,不需要預先指定連結串列長度,理論上鍊表可以無限長,直到記憶體耗盡。連結串列會儲存下一個元素的地址,因此插入和刪除會很方便,但查詢指定元素時,最壞的情況是遍歷整個連結串列。

連結串列該怎麼使用?

這裡我用Java語言來簡單介紹下怎麼使用連結串列。

構建連結串列結構

//建立一個私有的靜態的Node泛型物件
public class LinkedList<E> {
Node<E> first;//第一個節點
Node<E> last;//最後一個節點
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;
    }
}
複製程式碼

在連結串列後插入元素,前面插入也類似

//中間變數儲存連結串列的最後一個節點
Node<E> l = last;
//構建新節點,頭節點指向連結串列的最後節點
Node<E> newNode = new Node<>(l, 5, null);
//把新節點當作最後一個節點
last = newNode;
//if 最後節點為空,說明是一個新連結串列
if (l == null)
    first = newNode;
//否則把連結串列最後一個節點的 next 節點指向新節點
else
    l.next = newNode;

複製程式碼

刪除指定節點 d

E element = d.item;
Node<E> next = d.next;
Node<E> prev = d.prev;
//if 當前節點的上一個節點為空,
//說明刪除的是第一個節點,
//把當前節點的下一個節點置為第一個節點。
if (prev == null) {
    first = next;
//否則把上一個節點的下一個節點指向當前節點的下一個節點,
//相當於跳過了當前節點,並把當前節點的上一個節點置空。
} else {
    prev.next = next;
    d.prev = null;
}
//if 當前節點的下一個節點為空,說明是最後一個節點。
//把最後一個節點置為上一個節點。
if (next == null) {
    last = prev;
//否則把當前的上一節點指向當前的下一個節點,
//相當於跳過當前節點,在把當前節點的下一個節點置空。
} else {
    next.prev = prev;
    d.next = null;
}
//置空當前節點元素,幫助 GC 回收
d.item = null;

複製程式碼

遍歷連結串列

Node<E> d = first;
while (d != null && d.next != null) {
    System.out.println(d.item);
    d = d.next;
}
複製程式碼

總結

陣列需要初始化確定好長度,並且不能修改陣列的長度。在有的場景下,是不知道有多少元素的,因此我們是不能準確的分配陣列的長度。但也提供了陣列擴容的方案,就是在現有的陣列大小上,在按一定演算法來建立一個新的陣列,並把陣列的資料拷貝進擴容後的陣列裡去,但陣列的擴容是很影響效能的。因此需要一種新的資料結構來儲存不能確定有多少元素的資料,這就是連結串列的應用場景。 但它也有缺點,每個節點多需要多的空間來儲存下一個節點的地址,查詢時最壞情況是遍歷整個陣列。 它的優點是不需要預分配固定大小,不限制元素個數,理論上可以直到記憶體耗盡,插入和刪除時間複雜度是O(1)。

相關文章