數據結構之「鏈表」

什麼是鏈表?

鏈表是一種線性表,但並不會按線性的順序存儲數據,而是在每個節點裏存儲到下一個節點的指針 (Pointer)。所以它不須要分配連續的存儲空間,也不須要預先固定元素的大小,它能夠動態的添加和刪除元素,並且時間複雜度是 O(1)。只不過查找某個元素時,時間複雜度是 O(n)。
鏈表有多種不一樣的類型:單向鏈表,雙向鏈表和循環鏈表。java

單向鏈表

單向鏈表是最簡單的一種,它包含兩個域,一個信息域和一個指針域。這個指針域指向列表中的下一個節點,而最後一個節點則指向一個空值。
單向鏈表算法

雙向鏈表

雙向鏈表中不只有指向後一個節點的指針,還有指向前一個節點的指針。這樣能夠從任何一個節點訪問前一個節點,固然也能夠訪問後一個節點。數組

雙向鏈表

循環鏈表

循環鏈表是把鏈表的首節點和末節點鏈接在一塊兒,造成一個環。這種方式在單向和雙向鏈表中皆可實現。數據結構

循環鏈表

鏈表有什麼做用?

根據鏈表的特性,動態的把元素加入到鏈表中,不須要預先指定鏈表長度,理論上鍊表能夠無限長,直到內存耗盡。鏈表會存儲下一個元素的地址,所以插入和刪除會很方便,但查詢指定元素時,最壞的狀況是遍歷整個鏈表。性能

鏈表該怎麼使用?

這裏我用 Java 語言來簡單實現鏈表,可參考 JDK 的 LinkedList。
構建鏈表結構this

//建立一個私有的靜態的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;
    }
}

在鏈表後插入元素,前面插入也相似spa

//中間變量存儲鏈表的最後一個節點
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;

遍歷鏈表code

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

總結

數組須要初始化肯定好長度,而且不能修改數組的長度。在有的場景下,是不知道有多少元素的,所以咱們是不能準確的分配數組的長度。但也提供了數組擴容的方案,就是在現有的數組大小上,在按必定算法來建立一個新的數組,並把數組的數據拷貝進擴容後的數組裏去,但數組的擴容是很影響性能的。所以須要一種新的數據結構來存儲不能肯定有多少元素的數據,這就是鏈表的應用場景。
但它也有缺點,每一個節點多須要多的空間來存儲下一個節點的地址,查詢時最壞狀況是遍歷整個數組。
它的優勢是不須要預分配固定大小,不限制元素個數,理論上能夠直到內存耗盡,插入和刪除時間複雜度是 O(1)。對象

PS:
清山綠水始於塵,博學多識貴於勤。
我有酒,你有故事嗎?
公衆號:「清塵閒聊」。
歡迎一塊兒談天說地,聊代碼。