feat: Traditional Chinese version (#1163)

* First commit

* Update mkdocs.yml

* Translate all the docs to traditional Chinese

* Translate the code files.

* Translate the docker file

* Fix mkdocs.yml

* Translate all the figures from SC to TC

* 二叉搜尋樹 -> 二元搜尋樹

* Update terminology.

* Update terminology

* 构造函数/构造方法 -> 建構子
异或 -> 互斥或

* 擴充套件 -> 擴展

* constant - 常量 - 常數

* 類	-> 類別

* AVL -> AVL 樹

* 數組 -> 陣列

* 係統 -> 系統
斐波那契數列 -> 費波那契數列
運算元量 -> 運算量
引數 -> 參數

* 聯絡 -> 關聯

* 麵試 -> 面試

* 面向物件 -> 物件導向
歸併排序 -> 合併排序
范式 -> 範式

* Fix 算法 -> 演算法

* 錶示 -> 表示
反碼 -> 一補數
補碼 -> 二補數
列列尾部 -> 佇列尾部
區域性性 -> 區域性
一摞 -> 一疊

* Synchronize with main branch

* 賬號 -> 帳號
推匯 -> 推導

* Sync with main branch

* First commit

* Update mkdocs.yml

* Translate all the docs to traditional Chinese

* Translate the code files.

* Translate the docker file

* Fix mkdocs.yml

* Translate all the figures from SC to TC

* 二叉搜尋樹 -> 二元搜尋樹

* Update terminology

* 构造函数/构造方法 -> 建構子
异或 -> 互斥或

* 擴充套件 -> 擴展

* constant - 常量 - 常數

* 類	-> 類別

* AVL -> AVL 樹

* 數組 -> 陣列

* 係統 -> 系統
斐波那契數列 -> 費波那契數列
運算元量 -> 運算量
引數 -> 參數

* 聯絡 -> 關聯

* 麵試 -> 面試

* 面向物件 -> 物件導向
歸併排序 -> 合併排序
范式 -> 範式

* Fix 算法 -> 演算法

* 錶示 -> 表示
反碼 -> 一補數
補碼 -> 二補數
列列尾部 -> 佇列尾部
區域性性 -> 區域性
一摞 -> 一疊

* Synchronize with main branch

* 賬號 -> 帳號
推匯 -> 推導

* Sync with main branch

* Update terminology.md

* 操作数量(num. of operations)-> 操作數量

* 字首和->前綴和

* Update figures

* 歸 -> 迴
記憶體洩漏 -> 記憶體流失

* Fix the bug of the file filter

* 支援 -> 支持
Add zh-Hant/README.md

* Add the zh-Hant chapter covers.
Bug fixes.

* 外掛 -> 擴充功能

* Add the landing page for zh-Hant version

* Unify the font of the chapter covers for the zh, en, and zh-Hant version

* Move zh-Hant/ to zh-hant/

* Translate terminology.md to traditional Chinese
This commit is contained in:
Yudong Jin
2024-04-06 02:30:11 +08:00
committed by GitHub
parent 33d7f8a2e5
commit 5f7385c8a3
1875 changed files with 102923 additions and 18 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+83
View File
@@ -0,0 +1,83 @@
# 圖
<u>圖(graph</u>是一種非線性資料結構,由<u>頂點(vertex</u>和<u>邊(edge</u>組成。我們可以將圖 $G$ 抽象地表示為一組頂點 $V$ 和一組邊 $E$ 的集合。以下示例展示了一個包含 5 個頂點和 7 條邊的圖。
$$
\begin{aligned}
V & = \{ 1, 2, 3, 4, 5 \} \newline
E & = \{ (1,2), (1,3), (1,5), (2,3), (2,4), (2,5), (4,5) \} \newline
G & = \{ V, E \} \newline
\end{aligned}
$$
如果將頂點看作節點,將邊看作連線各個節點的引用(指標),我們就可以將圖看作一種從鏈結串列拓展而來的資料結構。如下圖所示,**相較於線性關係(鏈結串列)和分治關係(樹),網路關係(圖)的自由度更高**,因而更為複雜。
![鏈結串列、樹、圖之間的關係](graph.assets/linkedlist_tree_graph.png)
## 圖的常見型別與術語
根據邊是否具有方向,可分為<u>無向圖(undirected graph</u>和<u>有向圖(directed graph</u>,如下圖所示。
- 在無向圖中,邊表示兩頂點之間的“雙向”連線關係,例如微信或 QQ 中的“好友關係”。
- 在有向圖中,邊具有方向性,即 $A \rightarrow B$ 和 $A \leftarrow B$ 兩個方向的邊是相互獨立的,例如微博或抖音上的“關注”與“被關注”關係。
![有向圖與無向圖](graph.assets/directed_graph.png)
根據所有頂點是否連通,可分為<u>連通圖(connected graph</u>和<u>非連通圖(disconnected graph</u>,如下圖所示。
- 對於連通圖,從某個頂點出發,可以到達其餘任意頂點。
- 對於非連通圖,從某個頂點出發,至少有一個頂點無法到達。
![連通圖與非連通圖](graph.assets/connected_graph.png)
我們還可以為邊新增“權重”變數,從而得到如下圖所示的<u>有權圖(weighted graph</u>。例如在《王者榮耀》等手遊中,系統會根據共同遊戲時間來計算玩家之間的“親密度”,這種親密度網路就可以用有權圖來表示。
![有權圖與無權圖](graph.assets/weighted_graph.png)
圖資料結構包含以下常用術語。
- <u>鄰接(adjacency</u>:當兩頂點之間存在邊相連時,稱這兩頂點“鄰接”。在上圖中,頂點 1 的鄰接頂點為頂點 2、3、5。
- <u>路徑(path</u>:從頂點 A 到頂點 B 經過的邊構成的序列被稱為從 A 到 B 的“路徑”。在上圖中,邊序列 1-5-2-4 是頂點 1 到頂點 4 的一條路徑。
- <u>度(degree</u>:一個頂點擁有的邊數。對於有向圖,<u>入度(in-degree</u>表示有多少條邊指向該頂點,<u>出度(out-degree</u>表示有多少條邊從該頂點指出。
## 圖的表示
圖的常用表示方式包括“鄰接矩陣”和“鄰接表”。以下使用無向圖進行舉例。
### 鄰接矩陣
設圖的頂點數量為 $n$ <u>鄰接矩陣(adjacency matrix</u>使用一個 $n \times n$ 大小的矩陣來表示圖,每一行(列)代表一個頂點,矩陣元素代表邊,用 $1$ 或 $0$ 表示兩個頂點之間是否存在邊。
如下圖所示,設鄰接矩陣為 $M$、頂點串列為 $V$ ,那麼矩陣元素 $M[i, j] = 1$ 表示頂點 $V[i]$ 到頂點 $V[j]$ 之間存在邊,反之 $M[i, j] = 0$ 表示兩頂點之間無邊。
![圖的鄰接矩陣表示](graph.assets/adjacency_matrix.png)
鄰接矩陣具有以下特性。
- 頂點不能與自身相連,因此鄰接矩陣主對角線元素沒有意義。
- 對於無向圖,兩個方向的邊等價,此時鄰接矩陣關於主對角線對稱。
- 將鄰接矩陣的元素從 $1$ 和 $0$ 替換為權重,則可表示有權圖。
使用鄰接矩陣表示圖時,我們可以直接訪問矩陣元素以獲取邊,因此增刪查改操作的效率很高,時間複雜度均為 $O(1)$ 。然而,矩陣的空間複雜度為 $O(n^2)$ ,記憶體佔用較多。
### 鄰接表
<u>鄰接表(adjacency list</u>使用 $n$ 個鏈結串列來表示圖,鏈結串列節點表示頂點。第 $i$ 個鏈結串列對應頂點 $i$ ,其中儲存了該頂點的所有鄰接頂點(與該頂點相連的頂點)。下圖展示了一個使用鄰接表儲存的圖的示例。
![圖的鄰接表表示](graph.assets/adjacency_list.png)
鄰接表僅儲存實際存在的邊,而邊的總數通常遠小於 $n^2$ ,因此它更加節省空間。然而,在鄰接表中需要透過走訪鏈結串列來查詢邊,因此其時間效率不如鄰接矩陣。
觀察上圖,**鄰接表結構與雜湊表中的“鏈式位址”非常相似,因此我們也可以採用類似的方法來最佳化效率**。比如當鏈結串列較長時,可以將鏈結串列轉化為 AVL 樹或紅黑樹,從而將時間效率從 $O(n)$ 最佳化至 $O(\log n)$ ;還可以把鏈結串列轉換為雜湊表,從而將時間複雜度降至 $O(1)$ 。
## 圖的常見應用
如下表所示,許多現實系統可以用圖來建模,相應的問題也可以約化為圖計算問題。
<p align="center"> 表 <id> &nbsp; 現實生活中常見的圖 </p>
| | 頂點 | 邊 | 圖計算問題 |
| -------- | ---- | -------------------- | ------------ |
| 社交網路 | 使用者 | 好友關係 | 潛在好友推薦 |
| 地鐵線路 | 站點 | 站點間的連通性 | 最短路線推薦 |
| 太陽系 | 星體 | 星體間的萬有引力作用 | 行星軌道計算 |
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@@ -0,0 +1,86 @@
# 圖的基礎操作
圖的基礎操作可分為對“邊”的操作和對“頂點”的操作。在“鄰接矩陣”和“鄰接表”兩種表示方法下,實現方式有所不同。
## 基於鄰接矩陣的實現
給定一個頂點數量為 $n$ 的無向圖,則各種操作的實現方式如下圖所示。
- **新增或刪除邊**:直接在鄰接矩陣中修改指定的邊即可,使用 $O(1)$ 時間。而由於是無向圖,因此需要同時更新兩個方向的邊。
- **新增頂點**:在鄰接矩陣的尾部新增一行一列,並全部填 $0$ 即可,使用 $O(n)$ 時間。
- **刪除頂點**:在鄰接矩陣中刪除一行一列。當刪除首行首列時達到最差情況,需要將 $(n-1)^2$ 個元素“向左上移動”,從而使用 $O(n^2)$ 時間。
- **初始化**:傳入 $n$ 個頂點,初始化長度為 $n$ 的頂點串列 `vertices` ,使用 $O(n)$ 時間;初始化 $n \times n$ 大小的鄰接矩陣 `adjMat` ,使用 $O(n^2)$ 時間。
=== "初始化鄰接矩陣"
![鄰接矩陣的初始化、增刪邊、增刪頂點](graph_operations.assets/adjacency_matrix_step1_initialization.png)
=== "新增邊"
![adjacency_matrix_add_edge](graph_operations.assets/adjacency_matrix_step2_add_edge.png)
=== "刪除邊"
![adjacency_matrix_remove_edge](graph_operations.assets/adjacency_matrix_step3_remove_edge.png)
=== "新增頂點"
![adjacency_matrix_add_vertex](graph_operations.assets/adjacency_matrix_step4_add_vertex.png)
=== "刪除頂點"
![adjacency_matrix_remove_vertex](graph_operations.assets/adjacency_matrix_step5_remove_vertex.png)
以下是基於鄰接矩陣表示圖的實現程式碼:
```src
[file]{graph_adjacency_matrix}-[class]{graph_adj_mat}-[func]{}
```
## 基於鄰接表的實現
設無向圖的頂點總數為 $n$、邊總數為 $m$ ,則可根據下圖所示的方法實現各種操作。
- **新增邊**:在頂點對應鏈結串列的末尾新增邊即可,使用 $O(1)$ 時間。因為是無向圖,所以需要同時新增兩個方向的邊。
- **刪除邊**:在頂點對應鏈結串列中查詢並刪除指定邊,使用 $O(m)$ 時間。在無向圖中,需要同時刪除兩個方向的邊。
- **新增頂點**:在鄰接表中新增一個鏈結串列,並將新增頂點作為鏈結串列頭節點,使用 $O(1)$ 時間。
- **刪除頂點**:需走訪整個鄰接表,刪除包含指定頂點的所有邊,使用 $O(n + m)$ 時間。
- **初始化**:在鄰接表中建立 $n$ 個頂點和 $2m$ 條邊,使用 $O(n + m)$ 時間。
=== "初始化鄰接表"
![鄰接表的初始化、增刪邊、增刪頂點](graph_operations.assets/adjacency_list_step1_initialization.png)
=== "新增邊"
![adjacency_list_add_edge](graph_operations.assets/adjacency_list_step2_add_edge.png)
=== "刪除邊"
![adjacency_list_remove_edge](graph_operations.assets/adjacency_list_step3_remove_edge.png)
=== "新增頂點"
![adjacency_list_add_vertex](graph_operations.assets/adjacency_list_step4_add_vertex.png)
=== "刪除頂點"
![adjacency_list_remove_vertex](graph_operations.assets/adjacency_list_step5_remove_vertex.png)
以下是鄰接表的程式碼實現。對比上圖,實際程式碼有以下不同。
- 為了方便新增與刪除頂點,以及簡化程式碼,我們使用串列(動態陣列)來代替鏈結串列。
- 使用雜湊表來儲存鄰接表,`key` 為頂點例項,`value` 為該頂點的鄰接頂點串列(鏈結串列)。
另外,我們在鄰接表中使用 `Vertex` 類別來表示頂點,這樣做的原因是:如果與鄰接矩陣一樣,用串列索引來區分不同頂點,那麼假設要刪除索引為 $i$ 的頂點,則需走訪整個鄰接表,將所有大於 $i$ 的索引全部減 $1$ ,效率很低。而如果每個頂點都是唯一的 `Vertex` 例項,刪除某一頂點之後就無須改動其他頂點了。
```src
[file]{graph_adjacency_list}-[class]{graph_adj_list}-[func]{}
```
## 效率對比
設圖中共有 $n$ 個頂點和 $m$ 條邊,下表對比了鄰接矩陣和鄰接表的時間效率和空間效率。
<p align="center"> 表 <id> &nbsp; 鄰接矩陣與鄰接表對比 </p>
| | 鄰接矩陣 | 鄰接表(鏈結串列) | 鄰接表(雜湊表) |
| ------------ | -------- | -------------- | ---------------- |
| 判斷是否鄰接 | $O(1)$ | $O(m)$ | $O(1)$ |
| 新增邊 | $O(1)$ | $O(1)$ | $O(1)$ |
| 刪除邊 | $O(1)$ | $O(m)$ | $O(1)$ |
| 新增頂點 | $O(n)$ | $O(1)$ | $O(1)$ |
| 刪除頂點 | $O(n^2)$ | $O(n + m)$ | $O(n)$ |
| 記憶體空間佔用 | $O(n^2)$ | $O(n + m)$ | $O(n + m)$ |
觀察上表,似乎鄰接表(雜湊表)的時間效率與空間效率最優。但實際上,在鄰接矩陣中操作邊的效率更高,只需一次陣列訪問或賦值操作即可。綜合來看,鄰接矩陣體現了“以空間換時間”的原則,而鄰接表體現了“以時間換空間”的原則。
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

@@ -0,0 +1,136 @@
# 圖的走訪
樹代表的是“一對多”的關係,而圖則具有更高的自由度,可以表示任意的“多對多”關係。因此,我們可以把樹看作圖的一種特例。顯然,**樹的走訪操作也是圖的走訪操作的一種特例**。
圖和樹都需要應用搜索演算法來實現走訪操作。圖的走訪方式也可分為兩種:<u>廣度優先走訪</u>和<u>深度優先走訪</u>。
## 廣度優先走訪
**廣度優先走訪是一種由近及遠的走訪方式,從某個節點出發,始終優先訪問距離最近的頂點,並一層層向外擴張**。如下圖所示,從左上角頂點出發,首先走訪該頂點的所有鄰接頂點,然後走訪下一個頂點的所有鄰接頂點,以此類推,直至所有頂點訪問完畢。
![圖的廣度優先走訪](graph_traversal.assets/graph_bfs.png)
### 演算法實現
BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入先出”的性質,這與 BFS 的“由近及遠”的思想異曲同工。
1. 將走訪起始頂點 `startVet` 加入列列,並開啟迴圈。
2. 在迴圈的每輪迭代中,彈出佇列首頂點並記錄訪問,然後將該頂點的所有鄰接頂點加入到佇列尾部。
3. 迴圈步驟 `2.` ,直到所有頂點被訪問完畢後結束。
為了防止重複走訪頂點,我們需要藉助一個雜湊表 `visited` 來記錄哪些節點已被訪問。
```src
[file]{graph_bfs}-[class]{}-[func]{graph_bfs}
```
程式碼相對抽象,建議對照下圖來加深理解。
=== "<1>"
![圖的廣度優先走訪步驟](graph_traversal.assets/graph_bfs_step1.png)
=== "<2>"
![graph_bfs_step2](graph_traversal.assets/graph_bfs_step2.png)
=== "<3>"
![graph_bfs_step3](graph_traversal.assets/graph_bfs_step3.png)
=== "<4>"
![graph_bfs_step4](graph_traversal.assets/graph_bfs_step4.png)
=== "<5>"
![graph_bfs_step5](graph_traversal.assets/graph_bfs_step5.png)
=== "<6>"
![graph_bfs_step6](graph_traversal.assets/graph_bfs_step6.png)
=== "<7>"
![graph_bfs_step7](graph_traversal.assets/graph_bfs_step7.png)
=== "<8>"
![graph_bfs_step8](graph_traversal.assets/graph_bfs_step8.png)
=== "<9>"
![graph_bfs_step9](graph_traversal.assets/graph_bfs_step9.png)
=== "<10>"
![graph_bfs_step10](graph_traversal.assets/graph_bfs_step10.png)
=== "<11>"
![graph_bfs_step11](graph_traversal.assets/graph_bfs_step11.png)
!!! question "廣度優先走訪的序列是否唯一?"
不唯一。廣度優先走訪只要求按“由近及遠”的順序走訪,**而多個相同距離的頂點的走訪順序允許被任意打亂**。以上圖為例,頂點 $1$、$3$ 的訪問順序可以交換,頂點 $2$、$4$、$6$ 的訪問順序也可以任意交換。
### 複雜度分析
**時間複雜度**:所有頂點都會入列並出隊一次,使用 $O(|V|)$ 時間;在走訪鄰接頂點的過程中,由於是無向圖,因此所有邊都會被訪問 $2$ 次,使用 $O(2|E|)$ 時間;總體使用 $O(|V| + |E|)$ 時間。
**空間複雜度**:串列 `res` ,雜湊表 `visited` ,佇列 `que` 中的頂點數量最多為 $|V|$ ,使用 $O(|V|)$ 空間。
## 深度優先走訪
**深度優先走訪是一種優先走到底、無路可走再回頭的走訪方式**。如下圖所示,從左上角頂點出發,訪問當前頂點的某個鄰接頂點,直到走到盡頭時返回,再繼續走到盡頭並返回,以此類推,直至所有頂點走訪完成。
![圖的深度優先走訪](graph_traversal.assets/graph_dfs.png)
### 演算法實現
這種“走到盡頭再返回”的演算法範式通常基於遞迴來實現。與廣度優先走訪類似,在深度優先走訪中,我們也需要藉助一個雜湊表 `visited` 來記錄已被訪問的頂點,以避免重複訪問頂點。
```src
[file]{graph_dfs}-[class]{}-[func]{graph_dfs}
```
深度優先走訪的演算法流程如下圖所示。
- **直虛線代表向下遞推**,表示開啟了一個新的遞迴方法來訪問新頂點。
- **曲虛線代表向上回溯**,表示此遞迴方法已經返回,回溯到了開啟此方法的位置。
為了加深理解,建議將下圖與程式碼結合起來,在腦中模擬(或者用筆畫下來)整個 DFS 過程,包括每個遞迴方法何時開啟、何時返回。
=== "<1>"
![圖的深度優先走訪步驟](graph_traversal.assets/graph_dfs_step1.png)
=== "<2>"
![graph_dfs_step2](graph_traversal.assets/graph_dfs_step2.png)
=== "<3>"
![graph_dfs_step3](graph_traversal.assets/graph_dfs_step3.png)
=== "<4>"
![graph_dfs_step4](graph_traversal.assets/graph_dfs_step4.png)
=== "<5>"
![graph_dfs_step5](graph_traversal.assets/graph_dfs_step5.png)
=== "<6>"
![graph_dfs_step6](graph_traversal.assets/graph_dfs_step6.png)
=== "<7>"
![graph_dfs_step7](graph_traversal.assets/graph_dfs_step7.png)
=== "<8>"
![graph_dfs_step8](graph_traversal.assets/graph_dfs_step8.png)
=== "<9>"
![graph_dfs_step9](graph_traversal.assets/graph_dfs_step9.png)
=== "<10>"
![graph_dfs_step10](graph_traversal.assets/graph_dfs_step10.png)
=== "<11>"
![graph_dfs_step11](graph_traversal.assets/graph_dfs_step11.png)
!!! question "深度優先走訪的序列是否唯一?"
與廣度優先走訪類似,深度優先走訪序列的順序也不是唯一的。給定某頂點,先往哪個方向探索都可以,即鄰接頂點的順序可以任意打亂,都是深度優先走訪。
以樹的走訪為例,“根 $\rightarrow$ 左 $\rightarrow$ 右”“左 $\rightarrow$ 根 $\rightarrow$ 右”“左 $\rightarrow$ 右 $\rightarrow$ 根”分別對應前序、中序、後序走訪,它們展示了三種走訪優先順序,然而這三者都屬於深度優先走訪。
### 複雜度分析
**時間複雜度**:所有頂點都會被訪問 $1$ 次,使用 $O(|V|)$ 時間;所有邊都會被訪問 $2$ 次,使用 $O(2|E|)$ 時間;總體使用 $O(|V| + |E|)$ 時間。
**空間複雜度**:串列 `res` ,雜湊表 `visited` 頂點數量最多為 $|V|$ ,遞迴深度最大為 $|V|$ ,因此使用 $O(|V|)$ 空間。
+9
View File
@@ -0,0 +1,9 @@
# 圖
![](../assets/covers/chapter_graph.jpg)
!!! abstract
在生命旅途中,我們就像是一個個節點,被無數看不見的邊相連。
每一次的相識與相離,都在這張巨大的網路圖中留下獨特的印記。
+31
View File
@@ -0,0 +1,31 @@
# 小結
### 重點回顧
- 圖由頂點和邊組成,可以表示為一組頂點和一組邊構成的集合。
- 相較於線性關係(鏈結串列)和分治關係(樹),網路關係(圖)具有更高的自由度,因而更為複雜。
- 有向圖的邊具有方向性,連通圖中的任意頂點均可達,有權圖的每條邊都包含權重變數。
- 鄰接矩陣利用矩陣來表示圖,每一行(列)代表一個頂點,矩陣元素代表邊,用 $1$ 或 $0$ 表示兩個頂點之間有邊或無邊。鄰接矩陣在增刪查改操作上效率很高,但空間佔用較多。
- 鄰接表使用多個鏈結串列來表示圖,第 $i$ 個鏈結串列對應頂點 $i$ ,其中儲存了該頂點的所有鄰接頂點。鄰接表相對於鄰接矩陣更加節省空間,但由於需要走訪鏈結串列來查詢邊,因此時間效率較低。
- 當鄰接表中的鏈結串列過長時,可以將其轉換為紅黑樹或雜湊表,從而提升查詢效率。
- 從演算法思想的角度分析,鄰接矩陣體現了“以空間換時間”,鄰接表體現了“以時間換空間”。
- 圖可用於建模各類現實系統,如社交網路、地鐵線路等。
- 樹是圖的一種特例,樹的走訪也是圖的走訪的一種特例。
- 圖的廣度優先走訪是一種由近及遠、層層擴張的搜尋方式,通常藉助佇列實現。
- 圖的深度優先走訪是一種優先走到底、無路可走時再回溯的搜尋方式,常基於遞迴來實現。
### Q & A
**Q**:路徑的定義是頂點序列還是邊序列?
維基百科上不同語言版本的定義不一致:英文版是“路徑是一個邊序列”,而中文版是“路徑是一個頂點序列”。以下是英文版原文:In graph theory, a path in a graph is a finite or infinite sequence of edges which joins a sequence of vertices.
在本文中,路徑被視為一個邊序列,而不是一個頂點序列。這是因為兩個頂點之間可能存在多條邊連線,此時每條邊都對應一條路徑。
**Q**:非連通圖中是否會有無法走訪到的點?
在非連通圖中,從某個頂點出發,至少有一個頂點無法到達。走訪非連通圖需要設定多個起點,以走訪到圖的所有連通分量。
**Q**:在鄰接表中,“與該頂點相連的所有頂點”的頂點順序是否有要求?
可以是任意順序。但在實際應用中,可能需要按照指定規則來排序,比如按照頂點新增的次序,或者按照頂點值大小的順序等,這樣有助於快速查詢“帶有某種極值”的頂點。