概況
與陣列類似,鍊錶是一種線性結構,如圖所示:
鍊錶結構與陣列結構有什麼區別呢?
現在假設有這樣乙個場景:目前系統擁有的剩餘記憶體空間充足,現在如果需要申請100mb的陣列或者鍊錶,系統中雖然剩餘空間大於100mb,但沒有大於或等於100mb的連續記憶體塊,那麼陣列將宣告成功,鍊錶因為不受記憶體連續影響,故而能夠申請成功。
基於最基本的鍊錶結構,鍊錶也衍生出了幾種不同的形式:
單鏈表——最簡單的鍊錶形式
其結構如果所示:
上面的結構由乙個個記憶體塊連線組成,每個記憶體塊稱為結點,結點由兩部分組成,一部分用來儲存資料,一部分用來純儲存下乙個節點的位址,也就是乙個指標,這個指標我們稱為後繼指標。
除此之外,鍊錶有兩個特殊的結點,即第乙個結點和最後乙個結點,我們習慣性把它們稱為頭結點和尾結點:
尾結點(tail):後繼指標為null,表示這是鍊錶的最後乙個結點。
鍊錶的插入、刪除、查詢操作
如下圖所示:
由上圖可知,鍊錶的插入與刪除操作非常簡單,只要經過一兩步對後繼指標的重新指向就可以完成,所以它們的時間複雜度為o(1)。
另外,由於鍊錶是由一系列零散的結點組成,無法進行類似陣列通過下標訪問對應結點的操作,查詢每個結點都要從頭結點開始一直遍歷,直到找到相應的結點,所以時間複雜度為o(n)。
迴圈鍊錶
其結構如圖所示:
就跟「迴圈鍊錶」這四個字所說的那樣,該結構通過尾結點的後繼指標指向頭指標形成乙個閉環結構,當要處理的資料具有環型結構特點時,就特別適合採用迴圈鍊錶,如著名的約瑟夫問題。
雙向鍊錶
雙向鍊錶是在單鏈表的基礎之上在每個結點上增加了乙個前驅指標(prev),以使得雙向訪問變得可能,如圖所示:
雙向鍊錶在結構上比單鏈表多了前驅指標,也就表示這種結構將會占用更多的記憶體,那麼在占用記憶體更高的情況下,其效能相比於單鏈表是怎樣的呢?
首先從插入操作的角度看:
然後從刪除操作的角度看:
最後,從查詢的角度思考:
一般的情況下,兩者都是遍歷查詢,時間複雜度為o(n),但假如鍊錶內的內容是有序的,雙向鍊錶會比單鏈表高效。因為我們每次查詢之後可以記錄上次查詢的位置p,然後根據查詢值與p的大小關係決定往前還是往後查詢,所以平均只需要查詢一半的資料。
雙向迴圈鍊錶
即雙向鍊錶與迴圈鍊錶的結合,如圖所示:
鍊錶與陣列時間複雜度比較
陣列鍊錶
插入和刪除(insert and delete)
o(n)
o(1)
隨機訪問(access)
o(1)
o(n)
以上是兩種資料結構一般情況下的時間複雜度,那麼我們能夠根據上面的時間複雜度來選擇使用哪種資料結構嗎?
不能,比如: 總結
和陣列相比,鍊錶更適合插入、刪除操作頻繁的場景,查詢的時間複雜度較高。不過,在具體軟體開發中,要對陣列和鍊錶的各種效能進行對比,綜合來選擇使用兩者中的哪乙個。
另外,在日常coding中,我們可以採用用空間換時間或者時間換空間的思想:
資料結構 表之煉表
頭插法建立 尾插法建立 顯示 銷毀 include include using namespace std typedef int elemtype typedef struct lnode linklist void createlinklistf linklist l,elemtype a,in...
資料結構之鍊錶 一
線性表分為順序儲存結構和鏈式儲存結構2種。順序儲存結構的特點 任何乙個元素都可以進行隨即訪問,訪問速度高。但不適合瀕繁的插入和刪除操作。鏈式儲存結構 鍊錶 不可以隨即訪問元素。但適合頻繁的插入和刪除操作。乙個靜態鍊錶的例子 include struct node typedef struct nod...
資料結構之鍊錶(一)
很多人,一接觸到資料結構就難懂,就說有難度,還有就說,鍊錶有什麼用?今天我就詳細的說下,這個鍊錶有什麼用。一 鍊錶介紹 1 鍊錶有位址不連續的結點序列,必須通過指標相互連線。2 鍊錶的分類 1 單向線性鍊錶 每個節點中除了儲存資料結構內容以外,還需要儲存指向下乙個節點的指標,叫做後指標。最後乙個節點...