歡迎來到圖論(Graphs)的世界!

在本章中,我們將探索圖(Graphs)。雖然你可能會想到數學課裡的長條圖或折線圖,但在計算機科學中,「圖」是用來表示事物之間如何連接的一種方式。

試想一下 Facebook:你是其中的一個「點」,而友誼就是連接你與他人的「線」。或者想想 Google 地圖:城市是點,道路是線。圖在我們的生活中無處不在!如果一開始覺得這概念有點抽象也別擔心,我們會把它拆解成小部分來學習。

1. 基礎概念:什麼是圖?

圖(Graph)是一種用於表示對象對之間複雜關係的數學結構。它由兩個主要部分組成:

頂點(Vertex 或 Node):圖中的「對象」或「點」(例如一個人或一個城市)。
邊(Edge 或 Arc):連接頂點之間的「線」(例如一段友誼或一條道路)。

有向圖(Directed)與無向圖(Undirected)

想像節點 A 和 B 之間存在一種關係。

無向圖:邊沒有方向。如果 A 和 B 之間有一條邊,你可以雙向通行。
類比:雙向行車道或 Facebook 的好友關係(你們互為好友)。

有向圖:邊有特定的方向,通常用箭頭表示。你只能沿著箭頭的方向移動。
類比:單行道或 Twitter 的「追蹤」(你可能會追蹤某位名人,但對方不一定會追蹤你!)。

加權圖(Weighted Graphs)

有時候,節點之間的連接會有「成本」或「數值」。這被稱為加權圖。「權重(Weight)」可以代表距離、時間,甚至兩個城市之間航班的票價。

快速複習:
頂點(Vertex):一個點。
邊(Edge):一種連接。
加權(Weighted):連接帶有數值(例如:5 英里)。
有向(Directed):連接是單向的。

重點總結:圖只是節點及其之間連接的集合。它們能幫助我們建模所有事物,從網際網路到化學分子!

2. 電腦如何儲存圖

由於電腦無法直接「看見」圖的繪圖,我們需要一種方法將其轉化為數據。主要有兩種方法:

方法 A:鄰接矩陣(Adjacency Matrix)

這是一個二維陣列(格網)。行和列都代表頂點。如果兩個節點之間有連接,我們在對應位置填入 1;否則填入 0。對於加權圖,我們則在格網中儲存權重而非 1。

包含 3 個節點(A, B, C)的圖的矩陣示例:
\( \begin{matrix} & A & B & C \\ A & 0 & 1 & 0 \\ B & 1 & 0 & 1 \\ C & 0 & 1 & 0 \end{matrix} \)

方法 B:鄰接串列(Adjacency List)

這就像一本通訊錄。對於每個節點,我們保留一個清單,列出所有與它直接相連的其他節點。
示例:
A: [B]
B: [A, C]
C: [B]

哪種方法比較好?

鄰接矩陣:適合「稠密圖(Dense Graphs)」(幾乎所有節點都相連的情況)。它檢查「A 是否連接到 B?」非常快,但如果連接稀疏,儲存大量的 0 會浪費記憶體。
鄰接串列:適合「稀疏圖(Sparse Graphs)」(大部分節點沒有直接連接的情況)。它節省記憶體,因為只會儲存實際存在的連接。

你知道嗎?大多數現實世界中的圖,例如全球資訊網(World Wide Web),都是「稀疏」的。絕大多數網站只連結到所有網站中極小的一部分!

重點總結:連接多時用矩陣(速度快),連接少時用串列(節省空間)。

3. 圖的遍歷(Graph Traversal):探索連接

遍歷的意思是「訪問圖中的每一個節點」。根據你的目標,有兩種主要方法:

深度優先搜尋(Depth-First Search, DFS)

在 DFS 中,你會盡可能沿著一條路徑走到底,然後再回溯(back-tracking)去尋找新的路徑。
記憶小撇步:把「深度(Depth)」想像成「深(Deep)」。你潛入圖的深處。
類比:走迷宮時,沿著一條路徑一直走,直到遇到死胡同。
數據結構:使用堆疊(Stack)(後進先出,LIFO)。
常見用途:走迷宮或檢查兩點之間是否存在路徑。

廣度優先搜尋(Breadth-First Search, BFS)

在 BFS 中,你會先訪問起始節點的所有直接相鄰節點,然後再訪問它們的所有鄰居,依此類推。
記憶小撇步:把「廣度(Breadth)」想像成「寬(Wide)」。你在圖上向四面八方擴展。
類比:往池塘丟一顆石頭,看著漣漪一圈一圈向外擴散。
數據結構:使用佇列(Queue)(先進先出,FIFO)。
常見用途:在無權重圖中尋找最短路徑(例如:你在 LinkedIn 上與陌生人之間最少經過幾個「跳躍」)。

快速複習:
DFS:使用堆疊,深入探索,適合走迷宮。
BFS:使用佇列,廣泛擴散,尋找最短路徑(無權重圖)。

4. Dijkstra 最短路徑演算法

雖然 BFS 以「跳躍次數」來尋找最短路徑,但 Dijkstra 演算法是在邊有權重(例如英里或分鐘)時,尋找最短路徑的方法。

運作原理(核心概念):

1. 從起始節點開始,將其距離設為 0,將其他所有節點的距離設為「無限大」。
2. 查看當前節點的所有未訪問鄰居。
3. 計算到每個鄰居的距離:(當前節點的距離 + 邊的權重)
4. 如果這個新距離比該鄰居目前儲存的距離更小,就更新它!
5. 將當前節點標記為「已訪問」。你之後再也不會訪問它了。
6. 移動到距離最小的未訪問節點,重複上述步驟,直到所有節點都被訪問。

常見錯誤:學生常會忘記在發現更短的路徑時更新距離。務必檢查新計算的路徑是否比舊的「更便宜」!

現實世界應用:這正是你的衛星導航或 Google 地圖計算回家最快路線的方法。它將每個路口視為節點,將每條道路視為加權邊。

重點總結:Dijkstra 是在加權圖中尋找最短路線的「黃金標準」。它是一個最佳化(Optimisation)演算法。

5. 總結檢查清單

在完成本章之前,確保你可以:
• 定義頂點(Vertex)邊(Edge)
• 解釋有向圖無向圖的區別。
• 為簡單的圖繪製鄰接矩陣鄰接串列
• 描述 DFSBFS 如何探索圖,以及它們分別使用什麼數據結構。
• 解釋 Dijkstra 演算法的目的,並將其識別為加權圖中的最短路徑工具。

繼續練習手繪這些圖表——一旦你能畫出矩陣和串列,演算法的邏輯就會變得非常容易視覺化!