方格精選

🔯從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)
graph.add_node(nodeE)

# 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演算法的統整與比較

留言
avatar-img
留言分享你的想法!
小松鼠-avatar-img
發文者
2024/09/11
林燃(創作小說家)
小松鼠-avatar-img
發文者
2024/09/15
動手學Python/資料結構/演算法 的目錄提及了這篇文章,趕快過去看看吧!
avatar-img
小松鼠的演算法樂園
95會員
427內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/10/10
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
Thumbnail
2024/10/10
從Python 內建deque資料結構的角度切入, 同時了解deque 與 FIFO Queue相關的function用法。 collections.deque是一種兩端點皆可進出的雙端佇列 在兩端點高效地在O(1)常數時間內添加和刪除元素。 這使得deque非常適合實現FIFO Queue
Thumbnail
2024/09/27
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
Thumbnail
2024/09/27
井字遊戲(OOXX)的遊戲描述 Tic Tac Toe(井字遊戲)是經典的雙人棋盤遊戲,在一個3x3的方格中進行。 每回合兩個玩家輪流選一個位置,先讓自己的符號(是 X 或 O)在 水平線、垂直線或對角線上連成一線的玩家宣告獲勝。
Thumbnail
2024/09/23
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。
Thumbnail
2024/09/23
深入探討圖(Graph)的基本概念 及 最短路徑Shortest Path的尋找。 我們專注於廣度優先搜尋(BFS)演算法,以等權圖的最短路徑為例, 詳細說明如何利用BFS從起點擴散到終點,並且提供詳細的程式碼範例。 透過實作,讀者能夠更清楚理解圖論及BFS的應用,並體會水波紋擴散模型的重要性。
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。 節點Vertex: 節點
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。 節點Vertex: 節點
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。
Thumbnail
定義 圖Graph: 由節點和邊所組成的一個網狀資料結構。 圖的表達方式Graph representation: 常見的有相鄰串列adjacency list或相鄰矩陣adjacency matrix。 本文以adjacenct list作為示範。
Thumbnail
在資料結構與演算法裡, 最簡單的線性資料結構除了list之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list 在這篇文章,會從最基礎的Singly linked list開始講起。 定義
Thumbnail
在資料結構與演算法裡, 最簡單的線性資料結構除了list之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list 在這篇文章,會從最基礎的Singly linked list開始講起。 定義
Thumbnail
題目敘述 All Ancestors of a Node in a Directed Acyclic Graph 給定一個有向無環圖,請找出每個點的祖先,以陣列的形式返回答案。
Thumbnail
題目敘述 All Ancestors of a Node in a Directed Acyclic Graph 給定一個有向無環圖,請找出每個點的祖先,以陣列的形式返回答案。
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
Thumbnail
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
Thumbnail
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News