天天看點

什麼是連結清單? | 算法必看系列二什麼是連結清單

原文連結

什麼是連結清單

前言

如果說資料結構是算法的基礎,那麼數組和連結清單就是資料結構的基礎。因為像堆,棧,樹,圖等比較複雜的數組結基本上都可以由數組和連結清單來表示,是以掌握數組和連結清單的基本操作十分重要。

今天就來看看連結清單的基本操作及其在面試中的常見解題思路,本文将從以下幾個點來講解連結清單的核心知識

1.什麼是連結清單,連結清單的優缺點

2.連結清單的表示及基本操作

3.面試中連結清單的常見解題思路—翻轉

相信大家已經開始迫不及待地想用連結清單解題了,不過在開始之前我們還是要先來溫習下連結清單的定義,以及它的優勢與劣勢,磨刀不誤砍柴功!

連結清單的定義

連結清單是實體存儲單元上非連續的、非順序的存儲結構,它是由一個個結點,通過指針來聯系起來的,其中每個結點包括資料和指針。

什麼是連結清單? | 算法必看系列二什麼是連結清單

連結清單的非連續,非順序,對應數組的連續,順序,我們來看看整型數組 1,2,3,4 在記憶體中是如何表示的

什麼是連結清單? | 算法必看系列二什麼是連結清單

可以看到數組的每個元素都是連續緊鄰配置設定的,這叫連續性,同時由于數組的元素占用的大小是一樣的,在 Java 中 int 型大小固定為 4 個位元組,是以如果數組的起始位址是 100, 由于這些元素在記憶體中都是連續緊鄰配置設定的,大小也一樣,可以很容易地找出數組中任意一個元素的位置,比如數組中的第三個元素起始位址為 100 + 2 * 4 = 108,這就叫順序性。查找的時間複雜度是O(1),效率很高!

那連結清單在記憶體中是怎麼表示的呢

什麼是連結清單? | 算法必看系列二什麼是連結清單

可以看到每個結點都配置設定在非連續的位置,結點與結點之間通過指針連在了一起,是以如果我們要找比如值為 3 的結點時,隻能通過結點 1 從頭到尾周遊尋找,如果元素少還好,如果元素太多(比如超過一萬個),每個元素的查找都要從頭開始查找,時間複雜度是O(n),比起數組的 O(1),差距不小。

除了查找性能連結清單不如數組外,還有一個優勢讓數組的性能高于連結清單,這裡引入程式局部性原理,啥叫程式局部性原理。

我們知道 CPU 運作速度是非常快的,如果 CPU 每次運算都要到記憶體裡去取資料無疑是很耗時的,是以在 CPU 與記憶體之間往往內建了挺多層級的緩存,這些緩存越接近CPU,速度越快,是以如果能提前把記憶體中的資料加載到如下圖中的 L1, L2, L3 緩存中,那麼下一次 CPU 取數的話直接從這些緩存裡取即可,能讓CPU執行速度加快,那什麼情況下記憶體中的資料會被提前加載到 L1,L2,L3 緩存中呢,答案是當某個元素被用到的時候,那麼這個元素位址附近的的元素會被提前加載到緩存中

什麼是連結清單? | 算法必看系列二什麼是連結清單

以上文整型數組 1,2,3,4為例,當程式用到了數組中的第一個元素(即 1)時,由于 CPU 認為既然 1 被用到了,那麼緊鄰它的元素 2,3,4 被用到的機率會很大,是以會提前把 2,3,4 加到 L1,L2,L3 緩存中去,這樣 CPU 再次執行的時候如果用到 2,3,4,直接從 L1,L2,L3 緩存裡取就行了,能提升不少性能

畫外音:如果把 CPU 的一個時種看成一秒,則從 L1 讀取資料需要 3 秒,從 L2 讀取需要 11 秒,L3讀取需要 25秒,而從記憶體讀取呢,需要 1 分 40 秒,是以程式局部性原理能對 CPU 執行性能有很大的提升

而連結清單呢,由于連結清單的每個結點在記憶體裡都是随機分布的,隻是通過指針聯系在一起,是以這些結點的位址并不相鄰,自然無法利用 程式局部性原理 來提前加載到 L1,L2,L3 緩存中來提升程式性能。

畫外音:程式局部性原理是計算機中非常重要的原理,這裡不做展開,建議大家查閱相關資料詳細了解一下

如上所述,相比數組,連結清單的非連續,非順序确實讓它在性能上處于劣勢,那什麼情況下該使用連結清單呢?考慮以下情況

  • 大記憶體空間配置設定

由于數組空間的連續性,如果要為數組配置設定 500M 的空間,這 500M 的空間必須是連續的,未使用的,是以在記憶體空間的配置設定上數組的要求會比較嚴格,如果記憶體碎片太多,配置設定連續的大空間很可能導緻失敗。而連結清單由于是非連續的,是以這種情況下選擇連結清單更合适。

  • 元素頻繁删除和插入

如果涉及到元素的頻繁删除和插入,用連結清單就會高效很多,對于數組來說,如果要在元素間插入一個元素,需要把其餘元素一個個往後移(如圖示),以為新元素騰空間(同理,如果是删除則需要把被删除元素之後的元素一個個往前移),效率上無疑是比較低的。

(在 1,2 間插入 5,需要把2,3,4 同時往後移一位)

什麼是連結清單? | 算法必看系列二什麼是連結清單

後移:

什麼是連結清單? | 算法必看系列二什麼是連結清單

插入5:

什麼是連結清單? | 算法必看系列二什麼是連結清單

完成!

而連結清單的插入删除相對來說就比較簡單了,修改指針位置即可,其他元素無需做任何移動操作(如圖示:以插入為例)

什麼是連結清單? | 算法必看系列二什麼是連結清單
什麼是連結清單? | 算法必看系列二什麼是連結清單

完成:

什麼是連結清單? | 算法必看系列二什麼是連結清單

綜上所述:如果資料以查為主,很少涉及到增和删,選擇數組,如果資料涉及到頻繁的插入和删除,或元素所需配置設定空間過大,傾向于選擇連結清單。

說了這麼多理論,相信讀者對數組和連結清單的差別應該有了更深刻地認識了,尤其是程式局部性原理,是不是開了不少眼界^_^,如果面試中問到數組和連結清單的差別能回答到程式局部性原理,會是一個非常大的亮點!

了解更多算法内容,請持續關注:

阿裡雲開發者社群算法程式設計官方技術圈

!

下一節:連結清單的表示

來源 | 五分鐘學算法

作者 | 程式員小吳