Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 130 additions & 4 deletions Algorithms.Tests/Graph/Dijkstra/DijkstraTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,136 @@ public void DijkstraTest4_Success()
shortestPathList[2].ToString().Should()
.Be($"Vertex: {c} - Distance: {3} - Previous: {a}");

// Vertex D won't be visited in this dijkstra implementation which is valid only for cyclic graphs,
// since it is necessary to backtrack all unvisited vertices and place them
// to the priority queue, which is not implemented yet in this repository.
// If algo goes to the next vertex with minimal distance and this vertex is leaf -- algorithm stops.
shortestPathList[3].Vertex.Should().Be(d);
shortestPathList[3].Distance.Should().Be(8);
shortestPathList[3].PreviousVertex.Should().Be(c);
shortestPathList[3].ToString().Should()
.Be($"Vertex: {d} - Distance: {8} - Previous: {c}");
}

[Test]
public void DijkstraTest5_Success()
{
// here test case is from https://www.youtube.com/watch?v=pVfj6mxhdMw

var graph = new DirectedWeightedGraph<char>(7);
var a = graph.AddVertex('A');
var b = graph.AddVertex('B');
var c = graph.AddVertex('C');
var d = graph.AddVertex('D');
var e = graph.AddVertex('E');
var w = graph.AddVertex('W');
var z = graph.AddVertex('Z');

graph.AddEdge(a, b, 6);
graph.AddEdge(b, a, 6);

graph.AddEdge(a, d, 1);
graph.AddEdge(d, a, 1);

graph.AddEdge(d, e, 1);
graph.AddEdge(e, d, 1);

graph.AddEdge(d, b, 2);
graph.AddEdge(b, d, 2);

graph.AddEdge(e, b, 2);
graph.AddEdge(b, e, 2);

graph.AddEdge(e, c, 5);
graph.AddEdge(c, e, 5);

graph.AddEdge(c, b, 5);
graph.AddEdge(b, c, 5);

graph.AddEdge(a, w, 50);
graph.AddEdge(w, a, 50);

graph.AddEdge(w, z, 1);
graph.AddEdge(z, w, 1);

var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);
shortestPathList.Length.Should().Be(7);

shortestPathList[0].Vertex.Should().Be(a);
shortestPathList[0].Distance.Should().Be(0);
shortestPathList[0].PreviousVertex.Should().Be(a);
shortestPathList[0].ToString().Should()
.Be($"Vertex: {a} - Distance: {0} - Previous: {a}");

shortestPathList[1].Vertex.Should().Be(b);
shortestPathList[1].Distance.Should().Be(3);
shortestPathList[1].PreviousVertex.Should().Be(d);
shortestPathList[1].ToString().Should()
.Be($"Vertex: {b} - Distance: {3} - Previous: {d}");

shortestPathList[2].Vertex.Should().Be(c);
shortestPathList[2].Distance.Should().Be(7);
shortestPathList[2].PreviousVertex.Should().Be(e);
shortestPathList[2].ToString().Should()
.Be($"Vertex: {c} - Distance: {7} - Previous: {e}");

shortestPathList[3].Vertex.Should().Be(d);
shortestPathList[3].Distance.Should().Be(1);
shortestPathList[3].PreviousVertex.Should().Be(a);
shortestPathList[3].ToString().Should()
.Be($"Vertex: {d} - Distance: {1} - Previous: {a}");

shortestPathList[4].Vertex.Should().Be(e);
shortestPathList[4].Distance.Should().Be(2);
shortestPathList[4].PreviousVertex.Should().Be(d);
shortestPathList[4].ToString().Should()
.Be($"Vertex: {e} - Distance: {2} - Previous: {d}");

shortestPathList[5].Vertex.Should().Be(w);
shortestPathList[5].Distance.Should().Be(50);
shortestPathList[5].PreviousVertex.Should().Be(a);
shortestPathList[5].ToString().Should()
.Be($"Vertex: {w} - Distance: {50} - Previous: {a}");

shortestPathList[6].Vertex.Should().Be(z);
shortestPathList[6].Distance.Should().Be(51);
shortestPathList[6].PreviousVertex.Should().Be(w);
shortestPathList[6].ToString().Should()
.Be($"Vertex: {z} - Distance: {51} - Previous: {w}");
}

[Test]
public void DijkstraTest6_Success()
{
var graph = new DirectedWeightedGraph<char>(5);
var a = graph.AddVertex('A');
var b = graph.AddVertex('B');
var c = graph.AddVertex('C');
var d = graph.AddVertex('D');

graph.AddEdge(a, b, 1);
graph.AddEdge(b, a, 1);

graph.AddEdge(c, d, 5);
graph.AddEdge(d, c, 5);

var shortestPathList = DijkstraAlgorithm.GenerateShortestPath(graph, a);

shortestPathList.Length.Should().Be(4);
shortestPathList[0].Vertex.Should().Be(a);
shortestPathList[0].Distance.Should().Be(0);
shortestPathList[0].PreviousVertex.Should().Be(a);
shortestPathList[0].ToString().Should()
.Be($"Vertex: {a} - Distance: {0} - Previous: {a}");

shortestPathList[1].Vertex.Should().Be(b);
shortestPathList[1].Distance.Should().Be(1);
shortestPathList[1].PreviousVertex.Should().Be(a);
shortestPathList[1].ToString().Should()
.Be($"Vertex: {b} - Distance: {1} - Previous: {a}");

shortestPathList[2].Vertex.Should().Be(c);
shortestPathList[2].Distance.Should().Be(double.MaxValue);
shortestPathList[2].PreviousVertex.Should().BeNull();
shortestPathList[2].ToString().Should()
.Be($"Vertex: {c} - Distance: {double.MaxValue} - Previous: {null}");

shortestPathList[3].Vertex.Should().Be(d);
shortestPathList[3].Distance.Should().Be(double.MaxValue);
shortestPathList[3].PreviousVertex.Should().BeNull();
Expand Down
67 changes: 21 additions & 46 deletions Algorithms/Graph/Dijkstra/DijkstraAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,44 +25,43 @@ public static DistanceModel<T>[] GenerateShortestPath<T>(DirectedWeightedGraph<T

var distanceArray = InitializeDistanceArray(graph, startVertex);

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

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

while (true)
while (visitedVertices.Count != distanceArray.Length && distanceRecord.Count != 0)
{
visitedVertices.Add(currentVertex);
while(visitedVertices.Contains(distanceRecord.Peek().Vertex!))
{
distanceRecord.Dequeue();
}

var minDistance = distanceRecord.Dequeue();

var currentPath = minDistance.Distance;

visitedVertices.Add(minDistance.Vertex!);

var neighborVertices = graph
.GetNeighbors(currentVertex)
.GetNeighbors(minDistance.Vertex!)
.Where(x => x != null && !visitedVertices.Contains(x))
.ToList();

foreach (var vertex in neighborVertices)
{
var adjacentDistance = graph.AdjacentDistance(currentVertex, vertex!);
var adjacentDistance = graph.AdjacentDistance(minDistance.Vertex!, vertex!);

var distance = distanceArray[vertex!.Index];

if (distance.Distance <= currentPath + adjacentDistance)
var fullDistance = currentPath + adjacentDistance;

if (distance.Distance > fullDistance)
{
continue;
distance.Distance = fullDistance;
distance.PreviousVertex = minDistance.Vertex;
distanceRecord.Enqueue(distance, fullDistance);
}

distance.Distance = currentPath + adjacentDistance;
distance.PreviousVertex = currentVertex;
}

var minimalAdjacentVertex = GetMinimalUnvisitedAdjacentVertex(graph, currentVertex, neighborVertices);

if (neighborVertices.Count == 0 || minimalAdjacentVertex is null)
{
break;
}

currentPath += graph.AdjacentDistance(currentVertex, minimalAdjacentVertex);

currentVertex = minimalAdjacentVertex;
}

return distanceArray;
Expand Down Expand Up @@ -96,28 +95,4 @@ private static void ValidateGraphAndStartVertex<T>(DirectedWeightedGraph<T> grap
throw new ArgumentNullException(nameof(graph));
}
}

private static Vertex<T>? GetMinimalUnvisitedAdjacentVertex<T>(
IDirectedWeightedGraph<T> graph,
Vertex<T> startVertex,
IEnumerable<Vertex<T>?> adjacentVertices)
{
var minDistance = double.MaxValue;
Vertex<T>? minVertex = default;

foreach (var vertex in adjacentVertices)
{
var currentDistance = graph.AdjacentDistance(startVertex, vertex!);

if (minDistance <= currentDistance)
{
continue;
}

minDistance = currentDistance;
minVertex = vertex;
}

return minVertex;
}
}