資結筆記|鏈結串列(linked list)

更新於 發佈於 閱讀時間約 8 分鐘

基本觀念


  鏈結串列(linked list)表面上也是一串數列,但與陣列不同的地方是,陣列的資料元素是在記憶體的連續空間,鏈結串列的資料是散落在記憶體的各處。而我們會將存放資料的地方稱為節點,每個節點包含2個區塊,一個區塊是資料區用來存放數據,另一個區塊是指標區用來指向下一個節點元素。

  下列是一個鏈結串列含有3個節點,要存放的內容為dog、cat、fish,我們來看看這個鏈結串列的外觀,如下圖,

raw-image

而實際上,因為鏈結串列是分散在記憶體的各處,所以有可能不是連續排列的,如下圖。但透過指標,可以將分散在各處的資料連結在一起。


raw-image

資料讀取


  鏈結串列讀取資料使用的是循序讀取(sequential access),必須得從頭開始讀取資料。以上面的鏈結陣列舉例,假設要讀取FISH,得先經過DOG->CAT->FISH,按照順序才能取得FISH的資料,因為要跑完整個串列,所以時間複雜度為O(n)。


新增&刪除節點元素


  在新增節點時,不需要搬動整個串列的資料,只需要將前一個元素的指標指向新元素,並將新元素的指標指向原本的下一個元素。例如我要將APPLE插入CAT和FISH中間,只要先將CAT指向APPLE(CAT->APPLE),然後再將APPLE指向FISH(APPL->FISH),即可形成DOG->CAT->APPLE->FISH,新的鏈結串列。

  刪除節點也是同樣的道理,只要將欲刪除的節點的前一個節點的指標,指向下一個節點,讓這個鏈結串列無法走到想刪除的節點,就算完成刪除節點的動作了。


循環鏈結串列


  在鏈結串列中有頭尾的觀念,搜尋時必須從頭至尾,但如果我們將最尾端的節點指向第一個節點,使它成為一個循環,就稱為循環鏈結串列。見下圖,這樣設計的好處是不管目前指標示指向哪一個節點,都可以搜尋整個串列,不會因為指到到尾巴而中止。

raw-image

陣列與鏈結串列時間複雜度比較


raw-image

由上述表格可知,不同的資料結構有各自的優缺點,會影響不同操作的時間複雜度,因此未來在設計程式時,可以根據需求決定要使用哪一種資料結構。



鏈結串列程式實作


  推薦大家一個實作程式碼可以使用的工具python tutor,不用特別安裝可以及時修改,還可以看到視覺化的資料結構,推薦初學者使用。


建立鏈結串列

class Node():
def __init__ (self, data=None):
self.data = data #資料data
self.next = None #指標pointer


p1 = Node(7) #節點1
p2 = Node(9) #節點2
p3 = Node(11) #節點3

p1.next = p2 #節點1指向節點2
p2.next = p3 #節點2指向節點3

# 設定頭節點
head = p1

# 輸出鏈結串列的內容
ptr = head
while ptr:
print(ptr.data, end=" -> ")
ptr = ptr.next
print("None") #移動指標到下一個節點


可以從上面的程式碼看到Node類別有兩個屬性,data是用來儲存節點的資料,next是用來儲存指標,指標會指向下一個節點。第一個節點為頭節點用head設定,如果陣列結束了就指向None,執行結果如下圖,

raw-image


插入新節點在開頭


  假設我要將一筆資料5插入這個鏈結串列成為新的頭節點,只需要新增一個節點(p0)並指向原本的頭節點(p1),並將新建的節點(p0)指定為新的頭節點。


class Node:
def __init__(self, data=None):
self.data = data # 節點儲存的資料
self.next = None # 下一個節點的指標(預設為 None)

# 創建初始的鏈結串列節點
p1 = Node(7) # 節點1
p2 = Node(9) # 節點2
p3 = Node(11) # 節點3

# 串接節點
p1.next = p2 # 節點1指向節點2
p2.next = p3 # 節點2指向節點3

# 新增節點到鏈結串列的最前面
p0 = Node(5) # 新的節點
p0.next = p1 # 新節點指向原本的第一個節點

# 設定新的頭節點
head = p0

# 輸出鏈結串列的內容
ptr = head
while ptr:
print(ptr.data, end=" -> ")
ptr = ptr.next
print("None")

執行結果如下圖,

raw-image


插入新節點在中間


  假設我要再新增一筆資料8在節點p1和p2中間,只需要新增一個節點(p4),將p1指向p4,再將p4指向P2則可以完成。


class Node:
def __init__(self, data=None):
self.data = data # 節點儲存的資料
self.next = None # 下一個節點的指標(預設為 None)

# 創建初始的鏈結串列節點
p0 = Node(5)
p1 = Node(7) # 節點1
p2 = Node(9) # 節點2
p3 = Node(11) # 節點3

# 新增節點在鏈結串列中間
p4 = Node(8) # 節點4

# 串接節點
p0.next = p1
p1.next = p4 # 節點1指向節點4
p2.next = p3
p4.next = p2 # 節點4指向節點2
# 設定頭節點

head = p0

# 輸出鏈結串列的內容

ptr = head

while ptr:

print(ptr.data, end=" -> ")

ptr = ptr.next

print("None")


raw-image


建立循環鏈結串列


  我們要建立一個循環連結只需將p3再指向p0即可,但輸出的時候要加入一個檢查機制,如果回到頭節點了則停止輸出,以避免無窮迴圈。


class Node:
def __init__(self, data=None):
self.data = data # 節點儲存的資料
self.next = None # 下一個節點的指標(預設為 None)

# 創建初始的鏈結串列節點
p0 = Node(5) # 節點0
p1 = Node(7) # 節點1
p2 = Node(9) # 節點2
p3 = Node(11) # 節點3

# 新增節點在鏈結串列中間
p4 = Node(8) # 節點4

# 串接節點
p0.next = p1 # 節點0指向節點1
p1.next = p4 # 節點1指向節點4
p4.next = p2 # 節點4指向節點2
p2.next = p3 # 節點2指向節點3
p3.next = p0 # 節點3指向節點0,形成循環鏈結串列

# 設定頭節點
head = p0

# 輸出循環鏈結串列的內容

ptr = head
while True:
print(ptr.data, end=" -> ")
ptr = ptr.next
if ptr == head: # 如果回到頭節點,停止遍歷
break
print(ptr.data, "(回到頭節點)")

以下是輸出結果,


raw-image


留言
avatar-img
留言分享你的想法!
avatar-img
資治通艦的沙龍
3會員
45內容數
人生中有的時候你會感知到,現在就是那個命運的分歧點,如果我不挽起袖子努力的話,我這一輩子大概就這樣了,所以我決定開始這個部落格,記錄我每天的努力,也希望可以分享學習的筆記與心得,大家可以一起交流學習。
資治通艦的沙龍的其他內容
2025/04/08
請使用 C 或 Java 語言寫一副程式,此副程式對一個長度為 10 的整數陣列 A[0:9],最多花費 15 次的數值比較運算,尋找陣列中的最小值及最大值,並分別存入 Min 及 Max。(注意:請加註解說明程式碼寫法) 【103.關務】
Thumbnail
2025/04/08
請使用 C 或 Java 語言寫一副程式,此副程式對一個長度為 10 的整數陣列 A[0:9],最多花費 15 次的數值比較運算,尋找陣列中的最小值及最大值,並分別存入 Min 及 Max。(注意:請加註解說明程式碼寫法) 【103.關務】
Thumbnail
2025/04/07
第 1 題 題目 設有一三維陣列(three dimensional matrix) A[1...u₁, 1...u₂, 1...u₃],請問其中一元素(element)A[i,j,k] 之儲存位置為何?其中 1 ≤ i ≤ u₁,1 ≤ j ≤ u₂,1 ≤ k ≤ u₃,請列出推導過程。
Thumbnail
2025/04/07
第 1 題 題目 設有一三維陣列(three dimensional matrix) A[1...u₁, 1...u₂, 1...u₃],請問其中一元素(element)A[i,j,k] 之儲存位置為何?其中 1 ≤ i ≤ u₁,1 ≤ j ≤ u₂,1 ≤ k ≤ u₃,請列出推導過程。
Thumbnail
2025/04/07
陣列和鏈結串列的比較以及陣列位址的計算方式
Thumbnail
2025/04/07
陣列和鏈結串列的比較以及陣列位址的計算方式
Thumbnail
看更多
你可能也想看
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
給定一個輸入陣列,每一個tuple代表節點之間了從屬關係。 請從從屬關係重建整顆二元樹,並且返回整顆二元樹的根結點。
Thumbnail
給定一個輸入陣列,每一個tuple代表節點之間了從屬關係。 請從從屬關係重建整顆二元樹,並且返回整顆二元樹的根結點。
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
給定一個字串陣列,請把它們所共有的字元伴隨著出現次數輸出。這篇文章介紹如何使用字典統計出現次數,和字典取交集的方法來解決此問題。並提供了複雜度分析和關鍵知識點。
Thumbnail
給定一個字串陣列,請把它們所共有的字元伴隨著出現次數輸出。這篇文章介紹如何使用字典統計出現次數,和字典取交集的方法來解決此問題。並提供了複雜度分析和關鍵知識點。
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
Thumbnail
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
Thumbnail
題目敘述 題目會給定我們一條鏈結串列Linked list的起始節點,要求我們刪除Linked List正中央的節點。 註: 正中央的節點,題目定義為索引為floor( 串列長度 / 2 ) 的節點,索引從零(Head Node)出發開始數。 例如 1 -> 2 -> 3 -> 4 鏈結
Thumbnail
題目敘述 題目會給定我們一條鏈結串列Linked list的起始節點,要求我們刪除Linked List正中央的節點。 註: 正中央的節點,題目定義為索引為floor( 串列長度 / 2 ) 的節點,索引從零(Head Node)出發開始數。 例如 1 -> 2 -> 3 -> 4 鏈結
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News