I've been looking for a way to implement both A* and Dijkstra to be able to get the shortest path and start to finish.
I retrieve a list of nodes and edges from a SQL database put the items into two dictionaries (Nodes and Edges) with the node/edge id as the keys.
The start (148309) and end (1483093) node I used to test, returns a result, but it visits 21 other nodes and should return 3 nodes (108.75m)

Attempting to use the pseduo code in the links below, I've managed to make it find the path but I'm struggling with the backtracing to get the actual shortest path it took. The links below don't mention this within their examples.
https://www.csharpstar.com/dijkstra-algorithm-csharp/
https://www.programmingalgorithms.com/algorithm/dijkstra's-algorithm/
https://www.dotnetlovers.com/article/234/dijkstras-shortest-path-algorithm
Objects
public class Node
{
public Node()
{
Edges = new Dictionary<long, Edge>();
}
public long Id { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
/// <summary>
/// The edges coming out of this node.
/// </summary>
public Dictionary<long, Edge> Edges { get; set; }
public double DistanceFromStart { get; set; }
public double DistanceToEnd { get; set; }
public bool Visited { get; set; }
/// <summary>
/// Specified the distance in KM between this node and the
/// specified node using their lat/longs.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public double DistanceTo(ref Node node)
{
return DistanceHelper.DistanceTo(this, node);
}
}
public class Edge
{
public long UID { get; set; }
public long StartNodeId { get; set; }
public long EndNodeId { get; set; }
public double Distance { get; set; }
public Node EndNode { get; set; }
}
public class SPResult
{
public double Distance { get; set; }
public long[] Nodes { get; set; }
public long[] Edges { get; set; }
}
Code so far.
public static Graph graph = new Graph();
static void Main(string[] args)
{
Console.WriteLine("Starting");
//Loads the nodes and edges from a SQL database.
LoadInfrastructure(3);
var res = graph.GetShortestPathDijkstra(1483099, 1483093);
//var res = graph.GetShortestPathDijkstra(1483129, 3156256);
Console.WriteLine("Done. Press any key to exit.");
Console.ReadKey();
}
public class Graph
{
public Graph()
{
Nodes = new Dictionary<long, Node>();
Edges = new Dictionary<long, Edge>();
}
Dictionary<long, Node> Nodes { get; set; }
Dictionary<long, Edge> Edges { get; set; }
Dictionary<long, double> queue;
Stopwatch stopwatch = new Stopwatch();
public void AddNode(Node n)
{
if (Nodes.ContainsKey(n.Id))
throw new Exception("Id already in graph.");
Nodes.Add(n.Id, n);
}
public void AddEdge(Edge e)
{
if (Edges.ContainsKey(e.UID))
throw new Exception("Id already in graph.");
e.EndNode = Nodes[e.EndNodeId];
Edges.Add(e.UID, e);
Nodes[e.StartNodeId].Edges.Add(e.UID, e);
}
public SPResult GetShortestPathDijkstra(long start, long end)
{
return GetShortestPathDijkstra(Nodes[start], Nodes[end]);
}
public SPResult GetShortestPathDijkstra(Node start, Node end)
{
if (!Nodes.ContainsKey(start.Id))
throw new Exception("Start node missing!");
if (!Nodes.ContainsKey(end.Id))
throw new Exception("End node missing!");
Console.WriteLine($"Finding shortest path between {start.Id} and {end.Id}...");
ResetNodes(null);
stopwatch.Restart();
Node current = start;
current.DistanceFromStart = 0;
queue.Add(start.Id, 0);
while (queue.Count > 0)
{
long minId = queue.OrderBy(x => x.Value).First().Key;
current = Nodes[minId];
queue.Remove(minId);
if (minId == end.Id)
{
current.Visited = true;
break;
}
foreach (var edge in current.Edges.OrderBy(ee => ee.Value.Distance))
{
var endNode = edge.Value.EndNode;
if (endNode.Visited)
continue;
double distance = current.DistanceFromStart + edge.Value.Distance;
if (queue.ContainsKey(endNode.Id))
{
if (queue[endNode.Id] > distance)
{
queue[endNode.Id] = endNode.Id;
Nodes[endNode.Id].DistanceFromStart = distance;
}
}
else
{
Nodes[endNode.Id].DistanceFromStart = distance;
queue.Add(endNode.Id, distance);
}
}
current.Visited = true;
}
stopwatch.Stop();
Console.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
Debug.WriteLine($"Found shortest path between {start.Id} and {end.Id} in {stopwatch.ElapsedMilliseconds}ms.");
**//Get path used.**
var rr = Nodes.Values.Where(nn => nn.Visited).OrderBy(nn => nn.DistanceFromStart).ToList();
return null;
}
public SPResult GetShortestPathAstar(long start, long end)
{
return GetShortestPathAstar(Nodes[start], Nodes[end]);
}
public SPResult GetShortestPathAstar(Node start, Node end)
{
ResetNodes(end);
start.DistanceFromStart = 0;
throw new NotImplementedException();
}
private void ResetNodes(Node endNode)
{
queue = new Dictionary<long, double>();
foreach (var node in Nodes)
{
node.Value.DistanceFromStart = double.PositiveInfinity;
node.Value.Visited = false;
if (endNode != null)
node.Value.DistanceToEnd = node.Value.DistanceTo(ref endNode);
}
}
}