Skip to content

Commit 0de6055

Browse files
author
Taras Nikulin
committed
Added code description
1 parent 3d48ed4 commit 0de6055

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

Dijkstra Algorithm/README.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,144 @@ From now we repeat all actions again and fill our table with new info!
132132
| Path Length From Start | 0 | 3 | 8 | 1 | 2 |
133133
| Path Vertices From Start | [A] | [A, B] | [A, B, C]| [A, D] | [A, D, E ] |
134134

135+
136+
## Code implementation
137+
First of all, lets create class, that will describe any Vertex in the graph.
138+
It is pretty simple
139+
```swift
140+
open class Vertex {
141+
142+
//Every vertex should be unique, that's why we set up identifier
143+
open var identifier: String
144+
145+
//For dijkstra every vertex in the graph should be connected with at least one other vertex. But there can be some use cases,
146+
//when you firstly initialize all vertices without neighbors. And then on next interation set up thei neighbors. So, initially neighbors is an empty array.
147+
//Array contains tuples (Vertex, Double). Vertex is a neighbor and Double is as edge weight to that neighbor.
148+
open var neighbors: [(Vertex, Double)] = []
149+
150+
//As it was mentioned in algorithm description, default path length from start for all vertices should be as much as possible.
151+
//It is var, because we will update it during algorithm execution.
152+
open var pathLengthFromStart = Double.infinity
153+
154+
//This array containt vertices, which we need to go through to reach this vertex from starting one
155+
//As with path length from start, we will change this array during algorithm execution.
156+
open var pathVerticesFromStart: [Vertex] = []
157+
158+
public init(identifier: String) {
159+
self.identifier = identifier
160+
}
161+
162+
//This function let us use the same array of vertices again and again to calculate paths with different starting vertex.
163+
//When we will need to set new starting vertex andd recalculate paths, then we will simply clear graph vertices' cashes.
164+
open func clearCache() {
165+
pathLengthFromStart = Double.infinity
166+
pathVerticesFromStart = []
167+
}
168+
}
169+
```
170+
171+
Because every vertex should be unique it is usefull to make them Hashable and according Equatable. We use identifier for this purposes.
172+
```swift
173+
extension Vertex: Hashable {
174+
open var hashValue: Int {
175+
return identifier.hashValue
176+
}
177+
}
178+
179+
extension Vertex: Equatable {
180+
public static func ==(lhs: Vertex, rhs: Vertex) -> Bool {
181+
return lhs.hashValue == rhs.hashValue
182+
}
183+
}
184+
```
185+
186+
We've created a base for our algorithm. Now let's create a house :)
187+
Dijkstra's realization is really straightforward.
188+
```swift
189+
public class Dijkstra {
190+
//It is a storage for vertices in the graph.
191+
//Assuming, that our vertices are unique, we can use Set instead of array. This approach will bring some benefits later.
192+
private var totalVertices: Set<Vertex>
193+
194+
public init(vertices: Set<Vertex>) {
195+
totalVertices = vertices
196+
}
197+
198+
//Remember clearCache function in the Vertex class implementation?
199+
//This is just a wrapper that cleans cache for all stored vertices.
200+
private func clearCache() {
201+
totalVertices.forEach { $0.clearCache() }
202+
}
203+
204+
public func findShortestPaths(from startVertex: Vertex) {
205+
//Before we start searching shortes path from startVertex,
206+
//we need to clear vertices cache just to be sure, that out graph is as clean as a baby.
207+
//Remember that every Vertex is a class and classes are passed by reference.
208+
//So whenever you change vertex outside of this class, it will affect this vertex inside totalVertices Set
209+
clearCache()
210+
//Now all our vertices have Double.infinity pathLengthFromStart and empty pathVerticesFromStart array.
211+
212+
//The next step in the algorithm is to set startVertex pathLengthFromStart and pathVerticesFromStart
213+
startVertex.pathLengthFromStart = 0
214+
startVertex.pathVerticesFromStart.append(startVertex)
215+
216+
//Here starts the main part. We will use while loop to iterate through all vertices in the graph.
217+
//For this purpose we define currentVertex variable, which we will change in the end of each while cycle.
218+
var currentVertex: Vertex? = startVertex
219+
220+
while let vertex = currentVertex {
221+
222+
//Nex line of code is an implementation of setting vertex as visited.
223+
//As it has been said, we should check only unvisited vertices in the graph,
224+
//So why don't just delete it from the set? This approach let us skip checking for *"if !vertex.visited then"*
225+
totalVertices.remove(vertex)
226+
227+
//filteredNeighbors is and arrray, that contains current vertex neighbors, which aren't yet visited
228+
let filteredNeighbors = vertex.neighbors.filter { totalVertices.contains($0.0) }
229+
230+
//Let's iterate through them
231+
for neighbor in filteredNeighbors {
232+
//These variable are more representative, than neighbor.0 or neighbor.1
233+
let neighborVertex = neighbor.0
234+
let weight = neighbor.1
235+
236+
//Here we calculate new weight, that we can offer to neighbor.
237+
let theoreticNewWeight = vertex.pathLengthFromStart + weight
238+
239+
//If it is smaller than neighbor's current pathLengthFromStart
240+
//Then we perform this code
241+
if theoreticNewWeight < neighborVertex.pathLengthFromStart {
242+
243+
//set new pathLengthFromStart
244+
neighborVertex.pathLengthFromStart = theoreticNewWeight
245+
246+
//set new pathVerticesFromStart
247+
neighborVertex.pathVerticesFromStart = vertex.pathVerticesFromStart
248+
249+
//append current vertex to neighbor's pathVerticesFromStart
250+
neighborVertex.pathVerticesFromStart.append(neighborVertex)
251+
}
252+
}
253+
254+
//If totalVertices is empty, i.e. all vertices are visited
255+
//Than break the loop
256+
if totalVertices.isEmpty {
257+
currentVertex = nil
258+
break
259+
}
260+
261+
//If loop is not broken, than pick next vertex for checkin from not visited.
262+
//Next vertex pathLengthFromStart should be the smallest one.
263+
currentVertex = totalVertices.min { $0.pathLengthFromStart < $1.pathLengthFromStart }
264+
}
265+
}
266+
}
267+
```
268+
269+
That's all! Now you can check this algorithm in the playground. On the main page there is a code for creating random graph.
270+
271+
Also there is a **VisualizedDijkstra.playground**. Use it to figure out algorithm flow in real (slowed :)) time.
272+
135273
## About this repository
136274

137275
This repository contains to playgrounds:

0 commit comments

Comments
 (0)