Skip to content

Commit c2c481a

Browse files
committed
Merge pull request kodecocodes#42 from chris-pilcher/breadth-first-search
Add breadth-first search
2 parents ea2c3fd + 2d24e5d commit c2c481a

File tree

18 files changed

+638
-1
lines changed

18 files changed

+638
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
func breadthFirstSearchMinimumSpanningTree(graph: Graph, source: Node) -> Graph {
2+
let minimumSpanningTree = graph.duplicate()
3+
4+
var queue = Queue<Node>()
5+
let sourceInMinimumSpanningTree = minimumSpanningTree.findNodeWithLabel(source.label)
6+
queue.enqueue(sourceInMinimumSpanningTree)
7+
sourceInMinimumSpanningTree.visited = true
8+
9+
while !queue.isEmpty {
10+
let current = queue.dequeue()!
11+
for edge in current.neighbors {
12+
let neighborNode = edge.neighbor
13+
if !neighborNode.visited {
14+
neighborNode.visited = true
15+
queue.enqueue(neighborNode)
16+
} else {
17+
current.remove(edge)
18+
}
19+
}
20+
}
21+
22+
return minimumSpanningTree
23+
}
24+
25+
/*:
26+
![Animated example of a breadth-first search](Minimum_Spanning_Tree.png)
27+
*/
28+
29+
let graph = Graph()
30+
31+
let nodeA = graph.addNode("a")
32+
let nodeB = graph.addNode("b")
33+
let nodeC = graph.addNode("c")
34+
let nodeD = graph.addNode("d")
35+
let nodeE = graph.addNode("e")
36+
let nodeF = graph.addNode("f")
37+
let nodeG = graph.addNode("g")
38+
let nodeH = graph.addNode("h")
39+
let nodeI = graph.addNode("i")
40+
41+
graph.addEdge(nodeA, neighbor: nodeB)
42+
graph.addEdge(nodeA, neighbor: nodeH)
43+
graph.addEdge(nodeB, neighbor: nodeA)
44+
graph.addEdge(nodeB, neighbor: nodeC)
45+
graph.addEdge(nodeB, neighbor: nodeH)
46+
graph.addEdge(nodeC, neighbor: nodeB)
47+
graph.addEdge(nodeC, neighbor: nodeD)
48+
graph.addEdge(nodeC, neighbor: nodeF)
49+
graph.addEdge(nodeC, neighbor: nodeI)
50+
graph.addEdge(nodeD, neighbor: nodeC)
51+
graph.addEdge(nodeD, neighbor: nodeE)
52+
graph.addEdge(nodeD, neighbor: nodeF)
53+
graph.addEdge(nodeE, neighbor: nodeD)
54+
graph.addEdge(nodeE, neighbor: nodeF)
55+
graph.addEdge(nodeF, neighbor: nodeC)
56+
graph.addEdge(nodeF, neighbor: nodeD)
57+
graph.addEdge(nodeF, neighbor: nodeE)
58+
graph.addEdge(nodeF, neighbor: nodeG)
59+
graph.addEdge(nodeG, neighbor: nodeF)
60+
graph.addEdge(nodeG, neighbor: nodeH)
61+
graph.addEdge(nodeG, neighbor: nodeI)
62+
graph.addEdge(nodeH, neighbor: nodeA)
63+
graph.addEdge(nodeH, neighbor: nodeB)
64+
graph.addEdge(nodeH, neighbor: nodeG)
65+
graph.addEdge(nodeH, neighbor: nodeI)
66+
graph.addEdge(nodeI, neighbor: nodeC)
67+
graph.addEdge(nodeI, neighbor: nodeG)
68+
graph.addEdge(nodeI, neighbor: nodeH)
69+
70+
let minimumSpanningTree = breadthFirstSearchMinimumSpanningTree(graph, source: nodeA)
71+
print(minimumSpanningTree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
func breadthFirstSearchShortestPath(graph: Graph, source: Node) {
2+
var queue = Queue<Node>()
3+
queue.enqueue(source)
4+
source.distance = 0
5+
6+
while !queue.isEmpty {
7+
let current = queue.dequeue()!
8+
for edge in current.neighbors {
9+
let neighborNode = edge.neighbor
10+
if !neighborNode.hasDistance {
11+
queue.enqueue(neighborNode)
12+
neighborNode.distance = current.distance! + 1
13+
}
14+
}
15+
}
16+
17+
print(graph.nodes)
18+
}
19+
20+
/*:
21+
![Animated example of a breadth-first search](Animated_BFS.gif)
22+
*/
23+
24+
let graph = Graph()
25+
26+
let nodeA = graph.addNode("a")
27+
let nodeB = graph.addNode("b")
28+
let nodeC = graph.addNode("c")
29+
let nodeD = graph.addNode("d")
30+
let nodeE = graph.addNode("e")
31+
let nodeF = graph.addNode("f")
32+
let nodeG = graph.addNode("g")
33+
let nodeH = graph.addNode("h")
34+
35+
graph.addEdge(nodeA, neighbor: nodeB)
36+
graph.addEdge(nodeA, neighbor: nodeC)
37+
graph.addEdge(nodeB, neighbor: nodeD)
38+
graph.addEdge(nodeB, neighbor: nodeE)
39+
graph.addEdge(nodeC, neighbor: nodeF)
40+
graph.addEdge(nodeC, neighbor: nodeG)
41+
graph.addEdge(nodeE, neighbor: nodeH)
42+
43+
breadthFirstSearchShortestPath(graph, source: nodeA)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
func breadthFirstSearch(graph: Graph, source: Node) {
2+
var seenNodes = [source]
3+
var queue = Queue<Node>()
4+
queue.enqueue(source)
5+
6+
print(source.label)
7+
8+
while !queue.isEmpty {
9+
let current = queue.dequeue()!
10+
for edge in current.neighbors {
11+
let neighborNode = edge.neighbor
12+
if !seenNodes.contains(neighborNode) {
13+
queue.enqueue(neighborNode)
14+
seenNodes.append(neighborNode)
15+
print(neighborNode.label)
16+
}
17+
}
18+
}
19+
}
20+
21+
/*:
22+
![Animated example of a breadth-first search](Animated_BFS.gif)
23+
*/
24+
25+
let graph = Graph()
26+
27+
let nodeA = graph.addNode("a")
28+
let nodeB = graph.addNode("b")
29+
let nodeC = graph.addNode("c")
30+
let nodeD = graph.addNode("d")
31+
let nodeE = graph.addNode("e")
32+
let nodeF = graph.addNode("f")
33+
let nodeG = graph.addNode("g")
34+
let nodeH = graph.addNode("h")
35+
36+
graph.addEdge(nodeA, neighbor: nodeB)
37+
graph.addEdge(nodeA, neighbor: nodeC)
38+
graph.addEdge(nodeB, neighbor: nodeD)
39+
graph.addEdge(nodeB, neighbor: nodeE)
40+
graph.addEdge(nodeC, neighbor: nodeF)
41+
graph.addEdge(nodeC, neighbor: nodeG)
42+
graph.addEdge(nodeE, neighbor: nodeH)
43+
44+
45+
breadthFirstSearch(graph, source: nodeA)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>
Loading
Loading
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class Edge {
2+
public var neighbor: Node
3+
4+
public init(neighbor: Node) {
5+
self.neighbor = neighbor
6+
}
7+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
public class Graph : CustomStringConvertible {
2+
public private(set) var nodes: [Node]
3+
4+
public init() {
5+
self.nodes = []
6+
}
7+
8+
public func addNode(label: String) -> Node {
9+
let node = Node(label: label)
10+
nodes.append(node)
11+
return node
12+
}
13+
14+
public func addEdge(source: Node, neighbor: Node) {
15+
let edge = Edge(neighbor: neighbor)
16+
edge.neighbor = neighbor
17+
source.neighbors.append(edge)
18+
}
19+
20+
public var description: String {
21+
var description = ""
22+
23+
for node in nodes {
24+
if !node.neighbors.isEmpty {
25+
description += "[node: \(node.label) edges: \(node.neighbors.map{ $0.neighbor.label})]"
26+
}
27+
}
28+
return description
29+
}
30+
31+
public func findNodeWithLabel(label: String) -> Node {
32+
return nodes.filter{ $0.label == label }.first!
33+
}
34+
35+
public func duplicate() -> Graph {
36+
let duplicated = Graph()
37+
38+
for node in nodes {
39+
duplicated.addNode(node.label)
40+
}
41+
42+
for node in nodes {
43+
for edge in node.neighbors {
44+
let source = duplicated.findNodeWithLabel(node.label)
45+
let neighbour = duplicated.findNodeWithLabel(edge.neighbor.label)
46+
duplicated.addEdge(source, neighbor: neighbour)
47+
}
48+
}
49+
50+
return duplicated
51+
}
52+
}

0 commit comments

Comments
 (0)