Skip to content

Commit 0ef9849

Browse files
authored
Fix Dijkstra algorithm (#499)
1 parent 0184c37 commit 0ef9849

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)