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
Loading
Loading
Loading

0 commit comments

Comments
 (0)