Skip to content

Commit 517e1cc

Browse files
committed
Fix Dijkstra algorithm
The original implementation of Dijkstra algorithm can't go through vertices which was counted previously. Add priority queue to fix it and modify the algorithm's test as well.
1 parent 0184c37 commit 517e1cc

File tree

2 files changed

+151
-50
lines changed

2 files changed

+151
-50
lines changed

Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs

Lines changed: 130 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,10 +190,136 @@ public void DijkstraTest4_Success()
190190
shortestPathList[2].ToString().Should()
191191
.Be($"Vertex: {c} - Distance: {3} - Previous: {a}");
192192

193-
// Vertex D won't be visited in this dijkstra implementation which is valid only for cyclic graphs,
194-
// since it is necessary to backtrack all unvisited vertices and place them
195-
// to the priority queue, which is not implemented yet in this repository.
196-
// If algo goes to the next vertex with minimal distance and this vertex is leaf -- algorithm stops.
193+
shortestPathList[3].Vertex.Should().Be(d);
194+
shortestPathList[3].Distance.Should().Be(8);
195+
shortestPathList[3].PreviousVertex.Should().Be(c);
196+
shortestPathList[3].ToString().Should()
197+
.Be($"Vertex: {d} - Distance: {8} - Previous: {c}");
198+
}
199+
200+
[Test]
201+
public void DijkstraTest5_Success()
202+
{
203+
// here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw
204+
205+
var graph = new DirectedWeightedGraph<char>(7);
206+
var a = graph.AddVertex('A');
207+
var b = graph.AddVertex('B');
208+
var c = graph.AddVertex('C');
209+
var d = graph.AddVertex('D');
210+
var e = graph.AddVertex('E');
211+
var w = graph.AddVertex('W');
212+
var z = graph.AddVertex('Z');
213+
214+
graph.AddEdge(a, b, 6);
215+
graph.AddEdge(b, a, 6);
216+
217+
graph.AddEdge(a, d, 1);
218+
graph.AddEdge(d, a, 1);
219+
220+
graph.AddEdge(d, e, 1);
221+
graph.AddEdge(e, d, 1);
222+
223+
graph.AddEdge(d, b, 2);
224+
graph.AddEdge(b, d, 2);
225+
226+
graph.AddEdge(e, b, 2);
227+
graph.AddEdge(b, e, 2);
228+
229+
graph.AddEdge(e, c, 5);
230+
graph.AddEdge(c, e, 5);
231+
232+
graph.AddEdge(c, b, 5);
233+
graph.AddEdge(b, c, 5);
234+
235+
graph.AddEdge(a, w, 50);
236+
graph.AddEdge(w, a, 50);
237+
238+
graph.AddEdge(w, z, 1);
239+
graph.AddEdge(z, w, 1);
240+
241+
var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);
242+
shortestPathList.Length.Should().Be(7);
243+
244+
shortestPathList[0].Vertex.Should().Be(a);
245+
shortestPathList[0].Distance.Should().Be(0);
246+
shortestPathList[0].PreviousVertex.Should().Be(a);
247+
shortestPathList[0].ToString().Should()
248+
.Be($"Vertex: {a} - Distance: {0} - Previous: {a}");
249+
250+
shortestPathList[1].Vertex.Should().Be(b);
251+
shortestPathList[1].Distance.Should().Be(3);
252+
shortestPathList[1].PreviousVertex.Should().Be(d);
253+
shortestPathList[1].ToString().Should()
254+
.Be($"Vertex: {b} - Distance: {3} - Previous: {d}");
255+
256+
shortestPathList[2].Vertex.Should().Be(c);
257+
shortestPathList[2].Distance.Should().Be(7);
258+
shortestPathList[2].PreviousVertex.Should().Be(e);
259+
shortestPathList[2].ToString().Should()
260+
.Be($"Vertex: {c} - Distance: {7} - Previous: {e}");
261+
262+
shortestPathList[3].Vertex.Should().Be(d);
263+
shortestPathList[3].Distance.Should().Be(1);
264+
shortestPathList[3].PreviousVertex.Should().Be(a);
265+
shortestPathList[3].ToString().Should()
266+
.Be($"Vertex: {d} - Distance: {1} - Previous: {a}");
267+
268+
shortestPathList[4].Vertex.Should().Be(e);
269+
shortestPathList[4].Distance.Should().Be(2);
270+
shortestPathList[4].PreviousVertex.Should().Be(d);
271+
shortestPathList[4].ToString().Should()
272+
.Be($"Vertex: {e} - Distance: {2} - Previous: {d}");
273+
274+
shortestPathList[5].Vertex.Should().Be(w);
275+
shortestPathList[5].Distance.Should().Be(50);
276+
shortestPathList[5].PreviousVertex.Should().Be(a);
277+
shortestPathList[5].ToString().Should()
278+
.Be($"Vertex: {w} - Distance: {50} - Previous: {a}");
279+
280+
shortestPathList[6].Vertex.Should().Be(z);
281+
shortestPathList[6].Distance.Should().Be(51);
282+
shortestPathList[6].PreviousVertex.Should().Be(w);
283+
shortestPathList[6].ToString().Should()
284+
.Be($"Vertex: {z} - Distance: {51} - Previous: {w}");
285+
}
286+
287+
[Test]
288+
public void DijkstraTest6_Success()
289+
{
290+
var graph = new DirectedWeightedGraph<char>(5);
291+
var a = graph.AddVertex('A');
292+
var b = graph.AddVertex('B');
293+
var c = graph.AddVertex('C');
294+
var d = graph.AddVertex('D');
295+
296+
graph.AddEdge(a, b, 1);
297+
graph.AddEdge(b, a, 1);
298+
299+
graph.AddEdge(c, d, 5);
300+
graph.AddEdge(d, c, 5);
301+
302+
var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);
303+
304+
shortestPathList.Length.Should().Be(4);
305+
shortestPathList[0].Vertex.Should().Be(a);
306+
shortestPathList[0].Distance.Should().Be(0);
307+
shortestPathList[0].PreviousVertex.Should().Be(a);
308+
shortestPathList[0].ToString().Should()
309+
.Be($"Vertex: {a} - Distance: {0} - Previous: {a}");
310+
311+
shortestPathList[1].Vertex.Should().Be(b);
312+
shortestPathList[1].Distance.Should().Be(1);
313+
shortestPathList[1].PreviousVertex.Should().Be(a);
314+
shortestPathList[1].ToString().Should()
315+
.Be($"Vertex: {b} - Distance: {1} - Previous: {a}");
316+
317+
shortestPathList[2].Vertex.Should().Be(c);
318+
shortestPathList[2].Distance.Should().Be(double.MaxValue);
319+
shortestPathList[2].PreviousVertex.Should().BeNull();
320+
shortestPathList[2].ToString().Should()
321+
.Be($"Vertex: {c} - Distance: {double.MaxValue} - Previous: {null}");
322+
197323
shortestPathList[3].Vertex.Should().Be(d);
198324
shortestPathList[3].Distance.Should().Be(double.MaxValue);
199325
shortestPathList[3].PreviousVertex.Should().BeNull();

Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs

Lines changed: 21 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,44 +25,43 @@ public static DistanceModel<T>[] GenerateShortestPath<T>(DirectedWeightedGraph<T
2525

2626
var distanceArray = InitializeDistanceArray(graph, startVertex);
2727

28-
var currentVertex = startVertex;
28+
var distanceRecord = new PriorityQueue<DistanceModel<T>, double>();
2929

30-
var currentPath = 0d;
30+
distanceRecord.Enqueue(distanceArray[0], distanceArray[0].Distance);
3131

32-
while (true)
32+
while (visitedVertices.Count != distanceArray.Length && distanceRecord.Count != 0)
3333
{
34-
visitedVertices.Add(currentVertex);
34+
while(visitedVertices.Contains(distanceRecord.Peek().Vertex!))
35+
{
36+
distanceRecord.Dequeue();
37+
}
38+
39+
var minDistance = distanceRecord.Dequeue();
40+
41+
var currentPath = minDistance.Distance;
42+
43+
visitedVertices.Add(minDistance.Vertex!);
3544

3645
var neighborVertices = graph
37-
.GetNeighbors(currentVertex)
46+
.GetNeighbors(minDistance.Vertex!)
3847
.Where(x => x != null && !visitedVertices.Contains(x))
3948
.ToList();
4049

4150
foreach (var vertex in neighborVertices)
4251
{
43-
var adjacentDistance = graph.AdjacentDistance(currentVertex, vertex!);
52+
var adjacentDistance = graph.AdjacentDistance(minDistance.Vertex!, vertex!);
4453

4554
var distance = distanceArray[vertex!.Index];
4655

47-
if (distance.Distance <= currentPath + adjacentDistance)
56+
var fullDistance = currentPath + adjacentDistance;
57+
58+
if (distance.Distance > fullDistance)
4859
{
49-
continue;
60+
distance.Distance = fullDistance;
61+
distance.PreviousVertex = minDistance.Vertex;
62+
distanceRecord.Enqueue(distance, fullDistance);
5063
}
51-
52-
distance.Distance = currentPath + adjacentDistance;
53-
distance.PreviousVertex = currentVertex;
5464
}
55-
56-
var minimalAdjacentVertex = GetMinimalUnvisitedAdjacentVertex(graph, currentVertex, neighborVertices);
57-
58-
if (neighborVertices.Count == 0 || minimalAdjacentVertex is null)
59-
{
60-
break;
61-
}
62-
63-
currentPath += graph.AdjacentDistance(currentVertex, minimalAdjacentVertex);
64-
65-
currentVertex = minimalAdjacentVertex;
6665
}
6766

6867
return distanceArray;
@@ -96,28 +95,4 @@ private static void ValidateGraphAndStartVertex<T>(DirectedWeightedGraph<T> grap
9695
throw new ArgumentNullException(nameof(graph));
9796
}
9897
}
99-
100-
private static Vertex<T>? GetMinimalUnvisitedAdjacentVertex<T>(
101-
IDirectedWeightedGraph<T> graph,
102-
Vertex<T> startVertex,
103-
IEnumerable<Vertex<T>?> adjacentVertices)
104-
{
105-
var minDistance = double.MaxValue;
106-
Vertex<T>? minVertex = default;
107-
108-
foreach (var vertex in adjacentVertices)
109-
{
110-
var currentDistance = graph.AdjacentDistance(startVertex, vertex!);
111-
112-
if (minDistance <= currentDistance)
113-
{
114-
continue;
115-
}
116-
117-
minDistance = currentDistance;
118-
minVertex = vertex;
119-
}
120-
121-
return minVertex;
122-
}
12398
}

0 commit comments

Comments
 (0)