Skip to content

Commit

Permalink
feat: add Swift codes for graph_traversal article (krahets#378)
Browse files Browse the repository at this point in the history
* feat: add Swift codes for graph_traversal article

* refactor: rename parameters

* Update graph_dfs.swift

---------

Co-authored-by: Yudong Jin <[email protected]>
  • Loading branch information
nuomi1 and krahets authored Feb 22, 2023
1 parent f2d2cca commit c6c4c9d
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 13 deletions.
6 changes: 6 additions & 0 deletions codes/swift/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ let package = Package(
// chapter_graph
.executable(name: "graph_adjacency_matrix", targets: ["graph_adjacency_matrix"]),
.executable(name: "graph_adjacency_list", targets: ["graph_adjacency_list"]),
.executable(name: "graph_bfs", targets: ["graph_bfs"]),
.executable(name: "graph_dfs", targets: ["graph_dfs"]),
// chapter_searching
.executable(name: "linear_search", targets: ["linear_search"]),
.executable(name: "binary_search", targets: ["binary_search"]),
Expand All @@ -49,7 +51,9 @@ let package = Package(
.executable(name: "radix_sort", targets: ["radix_sort"]),
],
targets: [
// helper
.target(name: "utils", path: "utils"),
.target(name: "graph_adjacency_list_target", dependencies: ["utils"], path: "chapter_graph", sources: ["graph_adjacency_list_target.swift"], swiftSettings: [.define("TARGET")]),
// chapter_computational_complexity
.executableTarget(name: "time_complexity", path: "chapter_computational_complexity", sources: ["time_complexity.swift"]),
.executableTarget(name: "worst_best_time_complexity", path: "chapter_computational_complexity", sources: ["worst_best_time_complexity.swift"]),
Expand Down Expand Up @@ -82,6 +86,8 @@ let package = Package(
// chapter_graph
.executableTarget(name: "graph_adjacency_matrix", dependencies: ["utils"], path: "chapter_graph", sources: ["graph_adjacency_matrix.swift"]),
.executableTarget(name: "graph_adjacency_list", dependencies: ["utils"], path: "chapter_graph", sources: ["graph_adjacency_list.swift"]),
.executableTarget(name: "graph_bfs", dependencies: ["utils", "graph_adjacency_list_target"], path: "chapter_graph", sources: ["graph_bfs.swift"]),
.executableTarget(name: "graph_dfs", dependencies: ["utils", "graph_adjacency_list_target"], path: "chapter_graph", sources: ["graph_dfs.swift"]),
// chapter_searching
.executableTarget(name: "linear_search", dependencies: ["utils"], path: "chapter_searching", sources: ["linear_search.swift"]),
.executableTarget(name: "binary_search", path: "chapter_searching", sources: ["binary_search.swift"]),
Expand Down
24 changes: 14 additions & 10 deletions codes/swift/chapter_graph/graph_adjacency_list.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
import utils

/* 基于邻接表实现的无向图类 */
class GraphAdjList {
public class GraphAdjList {
// 邻接表,使用哈希表来代替链表,以提升删除边、删除顶点的效率
// 请注意,adjList 中的元素是 Vertex 对象
private var adjList: [Vertex: [Vertex]]
public private(set) var adjList: [Vertex: [Vertex]]

/* 构造方法 */
init(edges: [[Vertex]]) {
public init(edges: [[Vertex]]) {
adjList = [:]
// 添加所有顶点和边
for edge in edges {
Expand All @@ -24,12 +24,12 @@ class GraphAdjList {
}

/* 获取顶点数量 */
func size() -> Int {
public func size() -> Int {
adjList.count
}

/* 添加边 */
func addEdge(vet1: Vertex, vet2: Vertex) {
public func addEdge(vet1: Vertex, vet2: Vertex) {
if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 {
fatalError("参数错误")
}
Expand All @@ -39,7 +39,7 @@ class GraphAdjList {
}

/* 删除边 */
func removeEdge(vet1: Vertex, vet2: Vertex) {
public func removeEdge(vet1: Vertex, vet2: Vertex) {
if adjList[vet1] == nil || adjList[vet2] == nil || vet1 == vet2 {
fatalError("参数错误")
}
Expand All @@ -49,7 +49,7 @@ class GraphAdjList {
}

/* 添加顶点 */
func addVertex(vet: Vertex) {
public func addVertex(vet: Vertex) {
if adjList[vet] != nil {
return
}
Expand All @@ -58,7 +58,7 @@ class GraphAdjList {
}

/* 删除顶点 */
func removeVertex(vet: Vertex) {
public func removeVertex(vet: Vertex) {
if adjList[vet] == nil {
fatalError("参数错误")
}
Expand All @@ -71,7 +71,7 @@ class GraphAdjList {
}

/* 打印邻接表 */
func print() {
public func print() {
Swift.print("邻接表 =")
for entry in adjList {
var tmp: [Int] = []
Expand All @@ -83,12 +83,14 @@ class GraphAdjList {
}
}

#if !TARGET

@main
enum GraphAdjacencyList {
/* Driver Code */
static func main() {
/* 初始化无向图 */
let v = Vertex.valsToVets([1, 3, 2, 5, 4])
let v = Vertex.valsToVets(vals: [1, 3, 2, 5, 4])
let edges = [[v[0], v[1]], [v[0], v[3]], [v[1], v[2]], [v[2], v[3]], [v[2], v[4]], [v[3], v[4]]]
let graph = GraphAdjList(edges: edges)
print("\n初始化后,图为")
Expand Down Expand Up @@ -119,3 +121,5 @@ enum GraphAdjacencyList {
graph.print()
}
}

#endif
56 changes: 56 additions & 0 deletions codes/swift/chapter_graph/graph_bfs.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* File: graph_bfs.swift
* Created Time: 2023-02-21
* Author: nuomi1 ([email protected])
*/

import graph_adjacency_list_target
import utils

/* 广度优先遍历 BFS */
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
func graphBFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
// 顶点遍历序列
var res: [Vertex] = []
// 哈希表,用于记录已被访问过的顶点
var visited: Set<Vertex> = [startVet]
// 队列用于实现 BFS
var que: [Vertex] = [startVet]
// 以顶点 vet 为起点,循环直至访问完所有顶点
while !que.isEmpty {
let vet = que.removeFirst() // 队首顶点出队
res.append(vet) // 记录访问顶点
// 遍历该顶点的所有邻接顶点
for adjVet in graph.adjList[vet] ?? [] {
if visited.contains(adjVet) {
continue // 跳过已被访问过的顶点
}
que.append(adjVet) // 只入队未访问的顶点
visited.insert(adjVet) // 标记该顶点已被访问
}
}
// 返回顶点遍历序列
return res
}

@main
enum GraphBFS {
/* Driver Code */
static func main() {
/* 初始化无向图 */
let v = Vertex.valsToVets(vals: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
let edges = [
[v[0], v[1]], [v[0], v[3]], [v[1], v[2]], [v[1], v[4]],
[v[2], v[5]], [v[3], v[4]], [v[3], v[6]], [v[4], v[5]],
[v[4], v[7]], [v[5], v[8]], [v[6], v[7]], [v[7], v[8]],
]
let graph = GraphAdjList(edges: edges)
print("\n初始化后,图为")
graph.print()

/* 广度优先遍历 BFS */
let res = graphBFS(graph: graph, startVet: v[0])
print("\n广度优先遍历(BFS)顶点序列为")
print(Vertex.vetsToVals(vets: res))
}
}
54 changes: 54 additions & 0 deletions codes/swift/chapter_graph/graph_dfs.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* File: graph_dfs.swift
* Created Time: 2023-02-21
* Author: nuomi1 ([email protected])
*/

import graph_adjacency_list_target
import utils

/* 深度优先遍历 DFS 辅助函数 */
func dfs(graph: GraphAdjList, visited: inout Set<Vertex>, res: inout [Vertex], vet: Vertex) {
res.append(vet) // 记录访问顶点
visited.insert(vet) // 标记该顶点已被访问
// 遍历该顶点的所有邻接顶点
for adjVet in graph.adjList[vet] ?? [] {
if visited.contains(adjVet) {
continue // 跳过已被访问过的顶点
}
// 递归访问邻接顶点
dfs(graph: graph, visited: &visited, res: &res, vet: adjVet)
}
}

/* 深度优先遍历 DFS */
// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点
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
}

@main
enum GraphDFS {
/* Driver Code */
static func main() {
/* 初始化无向图 */
let v = Vertex.valsToVets(vals: [0, 1, 2, 3, 4, 5, 6])
let edges = [
[v[0], v[1]], [v[0], v[3]], [v[1], v[2]],
[v[2], v[5]], [v[4], v[5]], [v[5], v[6]],
]
let graph = GraphAdjList(edges: edges)
print("\n初始化后,图为")
graph.print()

/* 深度优先遍历 DFS */
let res = graphDFS(graph: graph, startVet: v[0])
print("\n深度优先遍历(DFS)顶点序列为")
print(Vertex.vetsToVals(vets: res))
}
}
4 changes: 2 additions & 2 deletions codes/swift/utils/Vertex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class Vertex: Hashable {
}

/* 输入值列表 vals ,返回顶点列表 vets */
public static func valsToVets(_ vals: [Int]) -> [Vertex] {
public static func valsToVets(vals: [Int]) -> [Vertex] {
var vets: [Vertex] = []
for val in vals {
vets.append(Vertex(val: val))
Expand All @@ -30,7 +30,7 @@ public class Vertex: Hashable {
}

/* 输入顶点列表 vets ,返回值列表 vals */
public static func vetsToVals(_ vets: [Vertex]) -> [Int] {
public static func vetsToVals(vets: [Vertex]) -> [Int] {
var vals: [Int] = []
for vet in vets {
vals.append(vet.val)
Expand Down
4 changes: 3 additions & 1 deletion docs/chapter_graph/graph_traversal.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ BFS 常借助「队列」来实现。队列具有“先入先出”的性质,
=== "Swift"

```swift title="graph_bfs.swift"

[class]{}-[func]{graphBFS}
```

=== "Zig"
Expand Down Expand Up @@ -196,7 +196,9 @@ BFS 常借助「队列」来实现。队列具有“先入先出”的性质,
=== "Swift"

```swift title="graph_dfs.swift"
[class]{}-[func]{dfs}

[class]{}-[func]{graphDFS}
```

=== "Zig"
Expand Down

0 comments on commit c6c4c9d

Please sign in to comment.