patterncsharpMinor
Weighted graph and pathfinding implementation in C#
Viewed 0 times
pathfindinggraphweightedandimplementation
Problem
I am implementing fundamental data structures in C#. I have written a weighted graph in Java so my main motivation here is to sharpen my skills in C#. I have tested with various cases and there seems to be no logical issues, but I know the language could be better utilized.
The
As always, I am open to any general or specific advice.
```
class WeightedGraph
{
List> edges;
List> vertices;
public List> Edges { get { return edges; } }
public WeightedGraph(List> vertices, List> edges)
{
this.vertices = vertices;
this.edges = edges;
}
public void AddEdge(WeightedEdge newEdge)
{
edges.Add(newEdge);
}
public void RemoveEdge(WeightedEdge edge)
{
edges.Remove(edge);
}
///
/// Pathfinding algorithms available: Dijkstra and AStar
///
public List> Pathfinder(Vertex start, Vertex end, string algorithm)
{
Func, Vertex, List>> pathfinder;
if (algorithm == "Dijkstra")
{
pathfinder = DijkstraSearch;
}
else if (algorithm == "AStar")
{
pathfinder = AStarSearch;
}
else
{
throw new ArgumentException("Pathfinding algorithm not available.");
}
return pathfinder(start, end);
}
public List> DijkstraSearch(Vertex start, Vertex end)
{
Dictionary, Vertex> parentMap = new Dictionary, Vertex>();
PriorityQueue> priorityQueue = new PriorityQueue>();
InitializeCosts(start);
priorityQueue.Enqueue(start, start.Cost);
Vertex current;
while (priorityQueue.Count > 0)
{
The
Pathfinder method is not absolutely necessary, because the only difference with A and Dijkstra is the Heuristic. The reason I have it is two-fold. There are various optimizations of A that I would like to implement in the future. Thus I want it to be isolated. I also want to master delegates, hence the use of Func.As always, I am open to any general or specific advice.
WeightedGraph```
class WeightedGraph
{
List> edges;
List> vertices;
public List> Edges { get { return edges; } }
public WeightedGraph(List> vertices, List> edges)
{
this.vertices = vertices;
this.edges = edges;
}
public void AddEdge(WeightedEdge newEdge)
{
edges.Add(newEdge);
}
public void RemoveEdge(WeightedEdge edge)
{
edges.Remove(edge);
}
///
/// Pathfinding algorithms available: Dijkstra and AStar
///
public List> Pathfinder(Vertex start, Vertex end, string algorithm)
{
Func, Vertex, List>> pathfinder;
if (algorithm == "Dijkstra")
{
pathfinder = DijkstraSearch;
}
else if (algorithm == "AStar")
{
pathfinder = AStarSearch;
}
else
{
throw new ArgumentException("Pathfinding algorithm not available.");
}
return pathfinder(start, end);
}
public List> DijkstraSearch(Vertex start, Vertex end)
{
Dictionary, Vertex> parentMap = new Dictionary, Vertex>();
PriorityQueue> priorityQueue = new PriorityQueue>();
InitializeCosts(start);
priorityQueue.Enqueue(start, start.Cost);
Vertex current;
while (priorityQueue.Count > 0)
{
Solution
WeightedGraph
This class shoudln't implement any search algorithms. They need to be injected. Let's do this...
First you change the signature of the
you use the
you implement this interface in two classes, one for each search algorithm (here only one):
now if you call it like this:
instead of magic strings real magic happens ;-)
Access modifiers
Although not requried for private fields, it's a good habit to use them anyway to avoid any confusion.
Edges property
You provide additional methods for adding and removing edges... but currently the user is free to modify the list anyway becasue you expose it to him. Either remove the add/remove-edge methods or make the property
Search algorithms
I see that your search algorithms share one method:
If you don't want to repeat it in each algorithm you can as well create an abstract class that already implements it and derive the search algorithms from it:
This class shoudln't implement any search algorithms. They need to be injected. Let's do this...
First you change the signature of the
Pathfinder method to accept an interface instead of a magic string:public List> Pathfinder(Vertex start, Vertex end)
where TSearchAlgorithm : ISearchAlgorithm, new()
{
var searchAlgorithm = new TSearchAlgorithm();
return searchAlgorithm.Search(start, end);
}you use the
new() constraint to be able to create an instance of the generic argument that at the same time must implement the interface below that requires one method for searching:interface ISearchAlgorithm
{
List> Search(Vertex start, Vertex end);
}you implement this interface in two classes, one for each search algorithm (here only one):
class DijkstraSearchAlgorithm : ISearchAlgorithm
{
public List> Search(Vertex start, Vertex end)
{
...
}
}now if you call it like this:
weightedGraph.Pathfinder(..., ...);instead of magic strings real magic happens ;-)
Access modifiers
Although not requried for private fields, it's a good habit to use them anyway to avoid any confusion.
Edges property
List> edges;
public List> Edges { get { return edges; } }You provide additional methods for adding and removing edges... but currently the user is free to modify the list anyway becasue you expose it to him. Either remove the add/remove-edge methods or make the property
IReadOnlyCollection> so that he cannot change it.Search algorithms
I see that your search algorithms share one method:
ReconstructPath.If you don't want to repeat it in each algorithm you can as well create an abstract class that already implements it and derive the search algorithms from it:
interface ISearchAlgorithm
{
List> Search(Vertex start, Vertex end);
}
abstract class SearchAlgorithm : ISearchAlgorithm
{
public abstract List> Search(Vertex start, Vertex end);
protected List> ReconstructPath(Dictionary, Vertex> parentMap, Vertex start, Vertex end)
{
...
}
}
class DijkstraSearchAlgorithm : SearchAlgorithm
{
public override List> Search(Vertex start, Vertex end)
{
...
}
}Code Snippets
public List<Vertex<T>> Pathfinder<TSearchAlgorithm>(Vertex<T> start, Vertex<T> end)
where TSearchAlgorithm : ISearchAlgorithm, new()
{
var searchAlgorithm = new TSearchAlgorithm();
return searchAlgorithm.Search(start, end);
}interface ISearchAlgorithm
{
List<Vertex<T>> Search<T>(Vertex<T> start, Vertex<T> end);
}class DijkstraSearchAlgorithm : ISearchAlgorithm
{
public List<Vertex<T>> Search<T>(Vertex<T> start, Vertex<T> end)
{
...
}
}weightedGraph.Pathfinder<DijkstraSearchAlgorithm>(..., ...);List<WeightedEdge<T>> edges;
public List<WeightedEdge<T>> Edges { get { return edges; } }Context
StackExchange Code Review Q#138475, answer score: 2
Revisions (0)
No revisions yet.