mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-15 21:20:58 +00:00
build
This commit is contained in:
@@ -24,7 +24,11 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
2. 在迴圈的每輪迭代中,彈出佇列首頂點並記錄訪問,然後將該頂點的所有鄰接頂點加入到佇列尾部。
|
||||
3. 迴圈步驟 `2.` ,直到所有頂點被訪問完畢後結束。
|
||||
|
||||
為了防止重複走訪頂點,我們需要藉助一個雜湊表 `visited` 來記錄哪些節點已被訪問。
|
||||
為了防止重複走訪頂點,我們需要藉助一個雜湊集合 `visited` 來記錄哪些節點已被訪問。
|
||||
|
||||
!!! tip
|
||||
|
||||
雜湊集合可以看作一個只儲存 `key` 而不儲存 `value` 的雜湊表,它可以在 $O(1)$ 時間複雜度下進行 `key` 的增刪查改操作。根據 `key` 的唯一性,雜湊集合通常用於資料去重等場景。
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -34,7 +38,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊表,用於記錄已被訪問過的頂點
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = set[Vertex]([start_vet])
|
||||
# 佇列用於實現 BFS
|
||||
que = deque[Vertex]([start_vet])
|
||||
@@ -60,7 +64,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 頂點走訪序列
|
||||
vector<Vertex *> res;
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
unordered_set<Vertex *> visited = {startVet};
|
||||
// 佇列用於實現 BFS
|
||||
queue<Vertex *> que;
|
||||
@@ -91,7 +95,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
@@ -122,7 +126,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
List<Vertex> GraphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
HashSet<Vertex> visited = [startVet];
|
||||
// 佇列用於實現 BFS
|
||||
Queue<Vertex> que = new();
|
||||
@@ -153,7 +157,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
func graphBFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 頂點走訪序列
|
||||
res := make([]Vertex, 0)
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited := make(map[Vertex]struct{})
|
||||
visited[startVet] = struct{}{}
|
||||
// 佇列用於實現 BFS, 使用切片模擬佇列
|
||||
@@ -189,7 +193,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
func graphBFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 頂點走訪序列
|
||||
var res: [Vertex] = []
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
var visited: Set<Vertex> = [startVet]
|
||||
// 佇列用於實現 BFS
|
||||
var que: [Vertex] = [startVet]
|
||||
@@ -219,7 +223,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
function graphBFS(graph, startVet) {
|
||||
// 頂點走訪序列
|
||||
const res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited = new Set();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
@@ -250,7 +254,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
function graphBFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 頂點走訪序列
|
||||
const res: Vertex[] = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited: Set<Vertex> = new Set();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
@@ -281,7 +285,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = {};
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
@@ -313,7 +317,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 頂點走訪序列
|
||||
let mut res = vec![];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
let mut visited = HashSet::new();
|
||||
visited.insert(start_vet);
|
||||
// 佇列用於實現 BFS
|
||||
@@ -421,7 +425,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList<Vertex?> {
|
||||
// 頂點走訪序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
val visited = HashSet<Vertex>()
|
||||
visited.add(startVet)
|
||||
// 佇列用於實現 BFS
|
||||
@@ -447,7 +451,29 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="graph_bfs.rb"
|
||||
[class]{}-[func]{graph_bfs}
|
||||
### 廣度優先走訪 ###
|
||||
def graph_bfs(graph, start_vet)
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = Set.new([start_vet])
|
||||
# 佇列用於實現 BFS
|
||||
que = [start_vet]
|
||||
# 以頂點 vet 為起點,迴圈直至訪問完所有頂點
|
||||
while que.length > 0
|
||||
vet = que.shift # 佇列首頂點出隊
|
||||
res << vet # 記錄訪問頂點
|
||||
# 走訪該頂點的所有鄰接頂點
|
||||
for adj_vet in graph.adj_list[vet]
|
||||
next if visited.include?(adj_vet) # 跳過已被訪問的頂點
|
||||
que << adj_vet # 只入列未訪問的頂點
|
||||
visited.add(adj_vet) # 標記該頂點已被訪問
|
||||
end
|
||||
end
|
||||
# 返回頂點走訪序列
|
||||
res
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@@ -506,7 +532,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
|
||||
**時間複雜度**:所有頂點都會入列並出隊一次,使用 $O(|V|)$ 時間;在走訪鄰接頂點的過程中,由於是無向圖,因此所有邊都會被訪問 $2$ 次,使用 $O(2|E|)$ 時間;總體使用 $O(|V| + |E|)$ 時間。
|
||||
|
||||
**空間複雜度**:串列 `res` ,雜湊表 `visited` ,佇列 `que` 中的頂點數量最多為 $|V|$ ,使用 $O(|V|)$ 空間。
|
||||
**空間複雜度**:串列 `res` ,雜湊集合 `visited` ,佇列 `que` 中的頂點數量最多為 $|V|$ ,使用 $O(|V|)$ 空間。
|
||||
|
||||
## 9.3.2 深度優先走訪
|
||||
|
||||
@@ -518,7 +544,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
|
||||
### 1. 演算法實現
|
||||
|
||||
這種“走到盡頭再返回”的演算法範式通常基於遞迴來實現。與廣度優先走訪類似,在深度優先走訪中,我們也需要藉助一個雜湊表 `visited` 來記錄已被訪問的頂點,以避免重複訪問頂點。
|
||||
這種“走到盡頭再返回”的演算法範式通常基於遞迴來實現。與廣度優先走訪類似,在深度優先走訪中,我們也需要藉助一個雜湊集合 `visited` 來記錄已被訪問的頂點,以避免重複訪問頂點。
|
||||
|
||||
=== "Python"
|
||||
|
||||
@@ -539,7 +565,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊表,用於記錄已被訪問過的頂點
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = set[Vertex]()
|
||||
dfs(graph, visited, res, start_vet)
|
||||
return res
|
||||
@@ -566,7 +592,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
vector<Vertex *> graphDFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 頂點走訪序列
|
||||
vector<Vertex *> res;
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
unordered_set<Vertex *> visited;
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -594,7 +620,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -623,7 +649,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
List<Vertex> GraphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
HashSet<Vertex> visited = [];
|
||||
DFS(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -653,7 +679,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
func graphDFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 頂點走訪序列
|
||||
res := make([]Vertex, 0)
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited := make(map[Vertex]struct{})
|
||||
dfs(g, visited, &res, startVet)
|
||||
// 返回頂點走訪序列
|
||||
@@ -683,7 +709,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
func graphDFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 頂點走訪序列
|
||||
var res: [Vertex] = []
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
var visited: Set<Vertex> = []
|
||||
dfs(graph: graph, visited: &visited, res: &res, vet: startVet)
|
||||
return res
|
||||
@@ -713,7 +739,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
function graphDFS(graph, startVet) {
|
||||
// 頂點走訪序列
|
||||
const res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -747,7 +773,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
function graphDFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 頂點走訪序列
|
||||
const res: Vertex[] = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited: Set<Vertex> = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -780,7 +806,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = {};
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
@@ -811,7 +837,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 頂點走訪序列
|
||||
let mut res = vec![];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
let mut visited = HashSet::new();
|
||||
dfs(&graph, &mut visited, &mut res, start_vet);
|
||||
|
||||
@@ -882,7 +908,7 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList<Vertex?> {
|
||||
// 頂點走訪序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
val visited = HashSet<Vertex?>()
|
||||
dfs(graph, visited, res, startVet)
|
||||
return res
|
||||
@@ -892,9 +918,28 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
=== "Ruby"
|
||||
|
||||
```ruby title="graph_dfs.rb"
|
||||
[class]{}-[func]{dfs}
|
||||
### 深度優先走訪輔助函式 ###
|
||||
def dfs(graph, visited, res, vet)
|
||||
res << vet # 記錄訪問頂點
|
||||
visited.add(vet) # 標記該頂點已被訪問
|
||||
# 走訪該頂點的所有鄰接頂點
|
||||
for adj_vet in graph.adj_list[vet]
|
||||
next if visited.include?(adj_vet) # 跳過已被訪問的頂點
|
||||
# 遞迴訪問鄰接頂點
|
||||
dfs(graph, visited, res, adj_vet)
|
||||
end
|
||||
end
|
||||
|
||||
[class]{}-[func]{graph_dfs}
|
||||
### 深度優先走訪 ###
|
||||
def graph_dfs(graph, start_vet)
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = Set.new
|
||||
dfs(graph, visited, res, start_vet)
|
||||
res
|
||||
end
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
@@ -962,4 +1007,4 @@ BFS 通常藉助佇列來實現,程式碼如下所示。佇列具有“先入
|
||||
|
||||
**時間複雜度**:所有頂點都會被訪問 $1$ 次,使用 $O(|V|)$ 時間;所有邊都會被訪問 $2$ 次,使用 $O(2|E|)$ 時間;總體使用 $O(|V| + |E|)$ 時間。
|
||||
|
||||
**空間複雜度**:串列 `res` ,雜湊表 `visited` 頂點數量最多為 $|V|$ ,遞迴深度最大為 $|V|$ ,因此使用 $O(|V|)$ 空間。
|
||||
**空間複雜度**:串列 `res` ,雜湊集合 `visited` 頂點數量最多為 $|V|$ ,遞迴深度最大為 $|V|$ ,因此使用 $O(|V|)$ 空間。
|
||||
|
||||
Reference in New Issue
Block a user