關於鍊錶,首先我們要了解它和陣列的乙個最大區別:陣列需要一塊連續的記憶體空間來儲存,而鍊錶恰恰相反,它通過「指標」將一組零散的記憶體塊串聯起來使用。**實現可以參考這篇文章:**示例
關於鍊錶的時間複雜度,因為在對鍊錶執行插入和刪除操作時無需保持記憶體資料的連續性,而僅僅是修改一下指定節點的next指標指向,所以對應的時間複雜度是 o(1),但是因為不支援隨機訪問,只能通過節點的next指標進行遍歷,所以隨機訪問的時間複雜度是o(n)。
鍊錶結構五花八門,今天重點介紹四種最常見的鍊錶結構:單鏈表、雙向鍊錶、迴圈鍊錶以及雙向迴圈列表。
目錄
單鏈表迴圈鍊錶
雙向鍊錶
雙向迴圈鍊錶
內容小結
為了將所有的結點串起來,單鏈表的每個結點除了儲存資料之外,還需要記錄單鏈表上的下乙個結點的位置。我們把這個記錄下個結點位置的指標叫作後繼指標 next。
從上面的單鏈表圖中,可以明顯看出,其中有兩個結點是比較特殊的,它們分別是第乙個結點和最後乙個結點,即頭結點和尾結點,其中,頭結點用來記錄鍊錶的首位址,有了它,我們就可以遍歷得到整條鍊錶。而尾結點特殊的地方在於next指標指向的下乙個結點位置為空位址 null,表示這是鍊錶的結尾。
單向鍊錶和迴圈鍊錶都只有乙個方向,即只能通過結點的後繼指標 next 獲取後面的結點。而雙向鍊錶則不同,顧名思義,它支援兩個方向,每個結點不僅僅有乙個後繼指標 next ,還有乙個前驅指標 prev 指向其前面的結點。
相對於單向鍊錶,雖然雙向鍊錶占用的記憶體更多(多儲存了乙個前驅指標),但它的插入和刪除操作的效率卻有明顯提公升,可能這裡會有些疑問,本篇開頭的位置明明寫著鍊錶的插入和刪除的時間複雜度都是o(1),雙向鍊錶的效率還咋提公升呢?這裡請注意,前面說的時間複雜度都是指的是賦值操作,忽略了其查詢的過程,而雙向鍊錶的效率提公升就體現在其查詢過程,下面我們將查詢過程也統計下來,重新計算一下複雜度,以刪除操作為例:
(1)刪除結點中「值等於某個給定值」的結點
對於這種情況,不管是單鏈表還是雙向鍊錶,時間複雜度是一樣的,都是o(n)。為了查詢到值等於給定值的結點,都需要從頭結點開始乙個乙個依次遍歷對比,直到找到值等於給定值的結點,然後再通過我前面講的指標操作將其刪除。儘管單純的刪除操作時間複雜度是 o(1),但遍歷查詢的時間是主要的耗時點,對應的時間複雜度為 o(n)。根據時間複雜度分析中的加法法則,刪除值等於給定值的結點對應的鍊錶操作的總時間複雜度為 o(n),即不管是單鏈表還是雙向鍊錶,在這種情況下,時間複雜度都是o(n)。
(2)刪除給定指標指向的結點
對於這種情況,我們已經知道了要刪除的結點,假設為q,刪除q 需要知道其前驅結點p,將前驅結點的nex指標指向q的後驅結點,即可完成刪除,但單鏈表並不支援直接獲取前驅結點,所以為了找到前驅結點,我們還是要從頭結點開始遍歷鍊錶,直到 p->next==q,此時單項鍊表的複雜度為o(n)。但是對於雙向鍊錶來說就很簡單了,因為雙向鍊錶中的結點已經儲存了指向前驅結點的指標pre,無需再去遍歷。所以,此時雙向鍊錶的時間複雜度為 o(1)!
雙向迴圈鍊錶僅僅是修改了雙向鍊錶最後乙個結點的next指標使其指向鍊錶頭部,其他的和雙向鍊錶完全沒有任何區別。
本次主要介紹了幾種常見的鍊錶,包括單項鍊表、迴圈鍊錶、迴圈鍊錶、雙向迴圈鍊錶。和陣列相比,鍊錶更適合插入、刪除操作頻繁的場景,查詢的時間複雜度較高。資料結構與演算法之美 鍊錶
如何優雅的寫出鍊錶 6大學習技巧 一 理解指標或引用的含義1.含義 將某個變數 物件 賦值給指標 引用 實際上就是就是將這個變數 物件 的位址賦值給指標 引用 2.示例 p next q 表示p節點的後繼指標儲存了q節點的記憶體位址。p next p next next 表示p節點的後繼指標儲存了p...
資料結構與演算法之美 鍊錶
1.如何實現lru快取淘汰演算法 答 回答這個問題之前,我們首先了解一下什麼是快取 2.鍊錶的三種形式 單鏈表 雙向鍊錶 迴圈鍊錶 簡介一下單鏈表 頭節點用於記錄基位址,有了它我們就可以遍歷整條鍊錶,而尾節點特殊地方不是指向下乙個節點,而是指向乙個空位址。鍊錶因為不是乙個連續的位址,所以不需要考慮連...
《資料結構與演算法之美》筆記 鍊錶
typedef struct node node 陣列和鍊錶都是線性表。陣列必須是連續空間,而鍊錶無所謂。鍊錶 單鏈表 迴圈鍊錶 雙向鍊錶 陣列 插入 刪除的時間複雜度是o n 隨機訪問的時間複雜度是o 1 鍊錶 插入 刪除的時間複雜度是o 1 隨機訪問的時間複雜端是o n 快取淘汰策略 先進先出策...