Skip to content

Commit c0c5ffd

Browse files
Merge pull request #41 from 5sw/graphs
Depth-first and breadth-first search in graphs
2 parents c864c82 + 5ff494b commit c0c5ffd

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

DIRECTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* [Union Find](https://github.com/TheAlgorithms/Swift/blob/master/data_structures/union_find/union_find.swift)
5656

5757
## Graph
58+
* [Graph](https://github.com/TheAlgorithms/Swift/blob/master/graph/Graph.swift)
5859
* Bfs
5960
* [Bfs](https://github.com/TheAlgorithms/Swift/blob/master/graph/BFS/BFS.swift)
6061
* Dfs

graph/Graph.swift

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
struct GraphEdge<G: Graph> {
2+
var from: G.Node
3+
var to: G.Node
4+
var value: G.EdgeValue
5+
}
6+
7+
protocol Graph {
8+
typealias Edge = GraphEdge<Self>
9+
10+
associatedtype Node: Equatable
11+
associatedtype EdgeValue
12+
13+
func edges(from: Node) -> [Edge]
14+
}
15+
16+
struct AdjacencyList<Node: Hashable, EdgeValue>: Graph {
17+
typealias EdgeValue = EdgeValue
18+
typealias Node = Node
19+
20+
var graph: [Node: [Edge]] = [:]
21+
22+
func edges(from node: Node) -> [Edge] {
23+
graph[node, default: []]
24+
}
25+
26+
mutating func insert(from: Node, to: Node, value: EdgeValue) {
27+
graph[from, default: []].append(Edge(from: from, to: to, value: value))
28+
}
29+
30+
var allEdges: [Edge] {
31+
graph.values.flatMap { $0 }
32+
}
33+
}
34+
35+
extension AdjacencyList where EdgeValue == () {
36+
mutating func insert(from: Node, to: Node) {
37+
insert(from: from, to: to, value: ())
38+
}
39+
}
40+
41+
extension Graph {
42+
func depthFirstSearch(start: Node, destination: Node) -> [Edge]? {
43+
if start == destination {
44+
return []
45+
}
46+
47+
for edge in edges(from: start) {
48+
if let path = depthFirstSearch(start: edge.to, destination: destination) {
49+
return [edge] + path
50+
}
51+
}
52+
53+
return nil
54+
}
55+
}
56+
57+
extension Graph where Node: Hashable {
58+
func breadthFirstSearch(start: Node, destination: Node) -> [Edge]? {
59+
var queue: [(Node, [Edge])] = [(start, [])]
60+
var visited: Set<Node> = [start]
61+
62+
while !queue.isEmpty {
63+
let (current, path) = queue.removeFirst()
64+
if current == destination {
65+
return path
66+
}
67+
68+
for edge in edges(from: current) where visited.insert(edge.to).inserted {
69+
queue.append((edge.to, path + [edge]))
70+
}
71+
}
72+
73+
return nil
74+
}
75+
}
76+
77+
extension GraphEdge: CustomDebugStringConvertible {
78+
var debugDescription: String {
79+
if type(of: value) == Void.self {
80+
return "\(from) -- \(to)"
81+
} else {
82+
return "\(from) -\(value)- \(to)"
83+
}
84+
}
85+
}
86+
87+
var graph = AdjacencyList<String, Void>()
88+
graph.insert(from: "a", to: "b")
89+
graph.insert(from: "a", to: "d")
90+
graph.insert(from: "b", to: "c")
91+
graph.insert(from: "c", to: "d")
92+
93+
func test<G: Graph>(_ message: String, _ list: [GraphEdge<G>]?) {
94+
print(message)
95+
if let list = list {
96+
for edge in list {
97+
print(edge)
98+
}
99+
} else {
100+
print("Not found")
101+
}
102+
print("")
103+
}
104+
105+
test("Depth-first a -> d", graph.depthFirstSearch(start: "a", destination: "d"))
106+
test("Depth-first a -> e", graph.depthFirstSearch(start: "a", destination: "e"))
107+
108+
test("Breadth-first a -> d", graph.breadthFirstSearch(start: "a", destination: "d"))
109+
test("Breadth-first a -> e", graph.breadthFirstSearch(start: "a", destination: "e"))

0 commit comments

Comments
 (0)