Skip to content

Commit 5f4e339

Browse files
authored
Merge pull request kodecocodes#428 from crabman448/dijkstra
Dijkstra's algorithm
2 parents ae44a30 + 5428e53 commit 5f4e339

37 files changed

+1747
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//: Playground - noun: a place where people can play
2+
import Foundation
3+
4+
var vertices: Set<Vertex> = Set()
5+
6+
func createNotConnectedVertices() {
7+
//change this value to increase or decrease amount of vertices in the graph
8+
let numberOfVerticesInGraph = 15
9+
for i in 0..<numberOfVerticesInGraph {
10+
let vertex = Vertex(identifier: "\(i)")
11+
vertices.insert(vertex)
12+
}
13+
}
14+
15+
func setupConnections() {
16+
for vertex in vertices {
17+
//the amount of edges each vertex can have
18+
let randomEdgesCount = arc4random_uniform(4) + 1
19+
for _ in 0..<randomEdgesCount {
20+
//randomize weight value from 0 to 9
21+
let randomWeight = Double(arc4random_uniform(10))
22+
let neighborVertex = randomVertex(except: vertex)
23+
24+
//we need this check to set only one connection between two equal pairs of vertices
25+
if vertex.neighbors.contains(where: { $0.0 == neighborVertex }) {
26+
continue
27+
}
28+
//creating neighbors and setting them
29+
let neighbor1 = (neighborVertex, randomWeight)
30+
let neighbor2 = (vertex, randomWeight)
31+
vertex.neighbors.append(neighbor1)
32+
neighborVertex.neighbors.append(neighbor2)
33+
}
34+
}
35+
}
36+
37+
func randomVertex(except vertex: Vertex) -> Vertex {
38+
var newSet = vertices
39+
newSet.remove(vertex)
40+
let offset = Int(arc4random_uniform(UInt32(newSet.count)))
41+
let index = newSet.index(newSet.startIndex, offsetBy: offset)
42+
return newSet[index]
43+
}
44+
45+
func randomVertex() -> Vertex {
46+
let offset = Int(arc4random_uniform(UInt32(vertices.count)))
47+
let index = vertices.index(vertices.startIndex, offsetBy: offset)
48+
return vertices[index]
49+
}
50+
51+
//initialize random graph
52+
createNotConnectedVertices()
53+
setupConnections()
54+
55+
//initialize Dijkstra algorithm with graph vertices
56+
let dijkstra = Dijkstra(vertices: vertices)
57+
58+
//decide which vertex will be the starting one
59+
let startVertex = randomVertex()
60+
61+
let startTime = Date()
62+
63+
//ask algorithm to find shortest paths from start vertex to all others
64+
dijkstra.findShortestPaths(from: startVertex)
65+
66+
let endTime = Date()
67+
68+
print("calculation time is = \((endTime.timeIntervalSince(startTime))) sec")
69+
70+
//printing results
71+
let destinationVertex = randomVertex(except: startVertex)
72+
print(destinationVertex.pathLengthFromStart)
73+
var pathVerticesFromStartString: [String] = []
74+
for vertex in destinationVertex.pathVerticesFromStart {
75+
pathVerticesFromStartString.append(vertex.identifier)
76+
}
77+
78+
print(pathVerticesFromStartString.joined(separator: "->"))
79+
80+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Foundation
2+
3+
public class Dijkstra {
4+
private var totalVertices: Set<Vertex>
5+
6+
public init(vertices: Set<Vertex>) {
7+
totalVertices = vertices
8+
}
9+
10+
private func clearCache() {
11+
totalVertices.forEach { $0.clearCache() }
12+
}
13+
14+
public func findShortestPaths(from startVertex: Vertex) {
15+
clearCache()
16+
var currentVertices = self.totalVertices
17+
startVertex.pathLengthFromStart = 0
18+
startVertex.pathVerticesFromStart.append(startVertex)
19+
var currentVertex: Vertex? = startVertex
20+
while let vertex = currentVertex {
21+
currentVertices.remove(vertex)
22+
let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) }
23+
for neighbor in filteredNeighbors {
24+
let neighborVertex = neighbor.0
25+
let weight = neighbor.1
26+
27+
let theoreticNewWeight = vertex.pathLengthFromStart + weight
28+
if theoreticNewWeight < neighborVertex.pathLengthFromStart {
29+
neighborVertex.pathLengthFromStart = theoreticNewWeight
30+
neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart
31+
neighborVertex.pathVerticesFromStart.append(neighborVertex)
32+
}
33+
}
34+
if totalVertices.isEmpty {
35+
currentVertex = nil
36+
break
37+
}
38+
currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart }
39+
}
40+
}
41+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Foundation
2+
3+
open class Vertex {
4+
5+
open var identifier: String
6+
open var neighbors: [(Vertex, Double)] = []
7+
open var pathLengthFromStart = Double.infinity
8+
open var pathVerticesFromStart: [Vertex] = []
9+
10+
public init(identifier: String) {
11+
self.identifier = identifier
12+
}
13+
14+
open func clearCache() {
15+
pathLengthFromStart = Double.infinity
16+
pathVerticesFromStart = []
17+
}
18+
}
19+
20+
extension Vertex: Hashable {
21+
open var hashValue: Int {
22+
return identifier.hashValue
23+
}
24+
}
25+
26+
extension Vertex: Equatable {
27+
public static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
28+
return lhs.hashValue == rhs.hashValue
29+
}
30+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='ios'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

Dijkstra Algorithm/Dijkstra.playground/playground.xcworkspace/contents.xcworkspacedata

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
67.1 KB
Loading
35.1 KB
Loading
69.2 KB
Loading
74.7 KB
Loading
76.2 KB
Loading

0 commit comments

Comments
 (0)