方格精選

🔯從Python來學圖論Graph 與 DFS深度優先探索

閱讀時間約 1 分鐘

定義


圖Graph: 由節點和邊所組成的一個網狀資料結構


圖的表達方式Graph representation:
常見的有相鄰串列adjacency list相鄰矩陣adjacency matrix

本文以adjacenct list作為示範。


節點Vertex: 節點,也稱之為Node,圖的基本組成單元之一。


邊Edge: 邊,可分為有向邊Directed Edge,無向邊Undirected Edge

有向邊只能從起點走向終點。無向邊則可以雙向通過。

本文以有向邊作為示範。


深度優先拜訪DFS:
從某個指定的起點開始探索整張圖,只要找到某個相鄰的點還沒拜訪過,
就繼續遞迴拜訪下個對應的節點


深度優先拜訪DFS

優點

  1. 遞迴實現相對淺顯易懂
  2. 可以用來尋找指定的兩點之間是否有路徑存在
  3. 可以檢查Cycle環路是否存在
  4. 可以用來探索整張圖。

缺點

  1. 遞迴實現需要維護額外的run time call stack遞迴堆疊的時間成本與空間成本
  2. 找到的路徑未必保證是最短路徑(Not shortest path always)。

Graph的Class定義與建構子

class Graph:
def __init__(self):

# 節點清單​
self.nodes = []

Node的Class定義

class Node:
def __init__(self, value):

# 節點值​
self.value = value
# Edge list
self.edges = []

def add_edge(self, edge):

# 節點加入一條相連的有向邊​
self.edges.append(edge)

Edge的Class定義

class Edge:
def __init__(self, from_node, to_node):

# 起點
self.from_node = from_node

# 終點
self.to_node = to_node

Graph常見的操作

1.增加一個節點


在圖中新增一個節點,並且放入Graph圖裡的節點清單self.nodes。


時間複雜度 O(1)

raw-image
raw-image
raw-image
raw-image
raw-image
    def add_node(self, node):
self.nodes.append(node)

2.增加一條邊


在圖中新增一條邊,並且把這條邊放入起點的edge list。


時間複雜度 O(1)

raw-image
raw-image
raw-image
raw-image
raw-image
raw-image


    def add_edge(self, from_node, to_node):

# 根據(起點,終點) 建立一條邊
edge = Edge(from_node, to_node)

# 起點加入新的一條邊
from_node.add_edge(edge)



3.深度優先拜訪


從某個指定的起點開始探索整張圖,只要找到某個相鄰的點還沒拜訪過,

就繼續遞迴拜訪下個對應的節點


時間複雜度 O(V+E) 每個點至多拜訪一次,每條邊最多檢查一次

raw-image
raw-image
raw-image
raw-image
raw-image


    def dfs(self, start_node, visited=None):

if visited is None:
visited = set()

# 標記為已拜訪
visited.add(start_node)
print(start_node.value)

# DFS 遞迴拜訪下一個相鄰的節點
for edge in start_node.edges:

if edge.to_node not in visited:
self.dfs(edge.to_node, visited)

測試範例

raw-image

完整的Graph 與 DFS 深度優先拜訪實作和程式碼

class Node:
def __init__(self, value):
self.value = value
self.edges = []

def add_edge(self, edge):
self.edges.append(edge)

class Edge:
def __init__(self, from_node, to_node):
self.from_node = from_node
self.to_node = to_node

class Graph:
def __init__(self):
self.nodes = []

def add_node(self, node):
self.nodes.append(node)

def add_edge(self, from_node, to_node):
edge = Edge(from_node, to_node)
from_node.add_edge(edge)

def dfs(self, start_node, visited=None):
if visited is None:
visited = set()

visited.add(start_node)
print(start_node.value)
for edge in start_node.edges:
if edge.to_node not in visited:
self.dfs(edge.to_node, visited)

def demo():
# Graph and DFS demo

# Create Graph
graph = Graph()

# Create Node
nodeA = Node('A')
nodeB = Node('B')
nodeC = Node('C')
nodeD = Node('D')
nodeE = Node('E')

# Add node into Graph
graph.add_node(nodeA)
graph.add_node(nodeB)
graph.add_node(nodeC)
graph.add_node(nodeD)

# Add edge into Graph
graph.add_edge(nodeA, nodeB)
graph.add_edge(nodeA, nodeC)
graph.add_edge(nodeB, nodeD)
graph.add_edge(nodeB, nodeE)
graph.add_edge(nodeC, nodeD)

print("DFS traversal starting from node A:")
graph.dfs(nodeA)


if __name__ == '__main__':
demo()



測試輸出

DFS traversal starting from node A:
A
B
D
E
C

結語


其實Graph就是Node的組合與推廣,每個節點可以和數個不同的相鄰節點有邊相連

特化成鍊狀的Graph就是Linked List

特化成樹狀的Graph就是Tree, Binary Tree, Binary Search Tree, AVL Tree, ... 等等。


讀者可以透過紙筆追蹤演算法和程式執行邏輯,測試幾個簡單的小範例,


會有更深刻的了解和體會!


Graph圖論DFS相關的演算法練習題與詳解


🎄圖論應用: 二元樹的中序拜訪 Binary Tree Inorder Traversal_LC #94


🎄圖論應用: 二元樹的後序拜訪 Binary Tree Postorder Traversal_LC #145


🎄圖論應用: 樹的後序拜訪 N-ary Tree Postorder Traversal_Leetcode #590


尋寶之旅 挖掘最多金礦的走法 (DFS+最佳化)Leetcode #1219


DFS應用: 在二元樹插入新的一層 Add one row to Tree_Leetcode #623


合縱連橫: 從 路徑搜索 理解DFS背後的本質


合縱連橫: 從路徑和 理解 DFS+樹型DP 框架的本質。


DFS+DP解情境模擬題: 走出邊界的方法數 Out of Boundary Paths_Leetcode #576


DFS經典應用題 BST最靠近的公共祖先節點 Leetcode #235


二元樹的拜訪 結合 DFS深度優先模板


使用DFS 模板 + 基礎圖論題目 Binary Tree Paths Leetcode #257


Graph theory圖論 DFS、BFS演算法的統整與比較

80會員
416內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
Min-Heap 最小堆是一種特殊的樹狀資料結構, 其中每個節點的值都小於或等於其子節點的值。這意味著最小值總是位於根節點。 Min-Heap 常用於實作優先權佇列 (Priority Queue)、Dijkstra 演算法、 排序以及尋找中位數等應用。
Prefix Sum(前綴和)是一種用於計算陣列中任意區間和的高效方法。 前綴和算是一種犧牲空間換取時間效能提升的策略。 這在需要頻繁查詢區間和的情況下特別有用。 一開始,初始化時花費O(n)時間,掃描每個元素累加,建立一個prefix sum table, 接著,提供query介面查詢區間和
二元搜尋樹(Binary Search Tree,簡稱 BST)是一種特殊的二元樹結構, 具有以下特性: 左子樹:左子樹上所有節點的值均小於該節點的值。 右子樹:右子樹上所有節點的值均大於該節點的值。 無重複值:每個節點的值都是唯一的。 這些特性使得二元搜尋樹在搜尋、插入和刪除操作具有較佳的效能。
接著來進入圖論的重點之一,Tree與Binary Tree。 二元樹(Binary Tree)是一種樹狀數據結構,其中每個節點最多有兩個子節點,通常稱為左子節點和右子節點。這些子節點可以是其他節點或空節點(即無子節點)。 二元樹是其他進階樹的基礎,可延伸推廣到Binary Search Tree
今天,我們將用Python list來實現Disjoint Set (併查集,另外也有人稱之為Union-Find)。 Disjoint Set適合用於處理一些子集合的合併和根節點的查找操作。 這種資料結構在圖論中非常有用,特別是在解決連通性相關問題的應用。
在之前的教學中,已經學會了用雙向鏈結串列來實作Stack 堆疊。 今天,要用另一種底層資列結構,python list,來實作Stack 堆疊。 讀者可以從中發現,因為python list的功能和function實作已經很豐富, 所以使用起來,相當直覺,也簡單許多。
Min-Heap 最小堆是一種特殊的樹狀資料結構, 其中每個節點的值都小於或等於其子節點的值。這意味著最小值總是位於根節點。 Min-Heap 常用於實作優先權佇列 (Priority Queue)、Dijkstra 演算法、 排序以及尋找中位數等應用。
Prefix Sum(前綴和)是一種用於計算陣列中任意區間和的高效方法。 前綴和算是一種犧牲空間換取時間效能提升的策略。 這在需要頻繁查詢區間和的情況下特別有用。 一開始,初始化時花費O(n)時間,掃描每個元素累加,建立一個prefix sum table, 接著,提供query介面查詢區間和
二元搜尋樹(Binary Search Tree,簡稱 BST)是一種特殊的二元樹結構, 具有以下特性: 左子樹:左子樹上所有節點的值均小於該節點的值。 右子樹:右子樹上所有節點的值均大於該節點的值。 無重複值:每個節點的值都是唯一的。 這些特性使得二元搜尋樹在搜尋、插入和刪除操作具有較佳的效能。
接著來進入圖論的重點之一,Tree與Binary Tree。 二元樹(Binary Tree)是一種樹狀數據結構,其中每個節點最多有兩個子節點,通常稱為左子節點和右子節點。這些子節點可以是其他節點或空節點(即無子節點)。 二元樹是其他進階樹的基礎,可延伸推廣到Binary Search Tree
今天,我們將用Python list來實現Disjoint Set (併查集,另外也有人稱之為Union-Find)。 Disjoint Set適合用於處理一些子集合的合併和根節點的查找操作。 這種資料結構在圖論中非常有用,特別是在解決連通性相關問題的應用。
在之前的教學中,已經學會了用雙向鏈結串列來實作Stack 堆疊。 今天,要用另一種底層資列結構,python list,來實作Stack 堆疊。 讀者可以從中發現,因為python list的功能和function實作已經很豐富, 所以使用起來,相當直覺,也簡單許多。
你可能也想看
Thumbnail
八十-二十法則提到,在多數生活的現象中,約80%的效果是來自於20%的原因,除了經濟學、學習理論外,這個法則同樣也可以應用在生活中的幸福感上。 我們需要認知到擁有的越多不一定會越快樂,反而有可能會因為無法專注在少數事物上而產生空虛、迷茫的感覺。「極簡」精神最重要的一點在於放下對於「多」的執著,將有
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
在資料分析過程中,透過衡量變數之間的線性或非線性關係,能有效探索數據集,篩選出重要特徵,並進行預測建模。本文介紹瞭如何理解數據、使用相關矩陣找出變數關聯性,以及利用互資訊評估變數之間的依賴程度,幫助資料科學家在建模過程中選擇適當的變數,提升模型效果。
Thumbnail
Python資料視覺化在數據分析中扮演關鍵角色,透過視覺化捕捉數據模式、趨勢和異常,透過Matplotlib等工具創建專業圖表變相對簡單和高效。
Thumbnail
八十-二十法則提到,在多數生活的現象中,約80%的效果是來自於20%的原因,除了經濟學、學習理論外,這個法則同樣也可以應用在生活中的幸福感上。 我們需要認知到擁有的越多不一定會越快樂,反而有可能會因為無法專注在少數事物上而產生空虛、迷茫的感覺。「極簡」精神最重要的一點在於放下對於「多」的執著,將有
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
在資料分析過程中,透過衡量變數之間的線性或非線性關係,能有效探索數據集,篩選出重要特徵,並進行預測建模。本文介紹瞭如何理解數據、使用相關矩陣找出變數關聯性,以及利用互資訊評估變數之間的依賴程度,幫助資料科學家在建模過程中選擇適當的變數,提升模型效果。
Thumbnail
Python資料視覺化在數據分析中扮演關鍵角色,透過視覺化捕捉數據模式、趨勢和異常,透過Matplotlib等工具創建專業圖表變相對簡單和高效。