Node class
Node class
Edge class
Edge class
QueueItem class
QueueItem class
Program class
Stack Exchange network consists of 183 Q&A communities including Stack Overflow, the largest, most trusted online community for developers to learn, share their knowledge, and build their careers.
Visit Stack ExchangeTeams
Learn more about TeamsNode class
Edge class
QueueItem class
Program class
Node class
Edge class
QueueItem class
Program class
Here is my first attempt at refactoring. Instead of using a Tuple
, I used a STRUCT
and this made it more readable. I also extracted printing paths and finding paths into interfaces
so someone could print their own messages or implement there own path finding algorithm. The graph class has a corresponding interface
as well. I am still not sure if I need all the path finding methods, some of them are just one liners, so I wonder if they are necessary. I also want to pass a file name as an args parameter into main, but I am not sure how to get that to my CreateGraph
method. Also, IGraph graph = new Graph().CreateGraph();
seems a bit weird. Is this normal? I am also curious if there is a way to better pass in messages to my PrintXXXPath...
methods, so I don't have to have so many of them?
Node class
Any other refactorings are welcome?
public class Node
{
public string Name { get; private set; }
public List<Edge> Edges { get; private set; }
public Node(string name)
{
Name = name;
Edges = new List<Edge>();
}
public void AddEdge(Node targetNode, double weight)
{
Edges.Add(new Edge(targetNode,weight));
}
}
Edge class
public class Edge
{
public Node TargetNode { get; private set; }
public double Weight { get; private set; }
public Edge(Node targetNode, double weight)
{
TargetNode = targetNode;
Weight = weight;
}
}
QueueItem class
public class QueueItem
{
public Node Node { get; private set; }
public List<Edge> VisitedEdges { get; private set; }
public QueueItem(Node node, List<Edge> visitedEdges)
{
Node = node;
VisitedEdges = visitedEdges;
}
}
Path struct
public struct Path
{
public readonly Node StartNode;
public readonly Node EndNode;
public readonly string PathRepresentation;
public readonly int VisitedCount;
public readonly double TotalWeight;
public Path(Node startNode, Node endNode, string pathRepresentation, int visitedCount, double totalWeight)
{
StartNode = startNode;
EndNode = endNode;
PathRepresentation = pathRepresentation;
VisitedCount = visitedCount;
TotalWeight = totalWeight;
}
}
IGraph interface
public interface IGraph
{
void AddNode(string name);
Node GetNode(string name);
IGraph CreateGraph();
}
Graph class
public class Graph : IGraph
{
public Dictionary<string, Node> Nodes { get; private set; }
public Graph()
{
Nodes = new Dictionary<string, Node>();
}
public void AddNode(string name)
{
Nodes.Add(name, new Node(name));
}
public Node GetNode(string name)
{
if (Nodes.ContainsKey(name))
return Nodes[name];
return null;
}
public IGraph CreateGraph()
{
const int START_NODE_INDEX = 0;
const int END_NODE_INDEX = 1;
const int EDGE_WEIGHT_INDEX = 2;
var nodes = File.ReadAllText("graph.csv").Split(',');
IGraph graph = new Graph();
foreach (var n in nodes)
{
var node = n.Trim();
if (graph.GetNode(node[START_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[START_NODE_INDEX].ToString());
}
if (graph.GetNode(node[END_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[END_NODE_INDEX].ToString());
}
graph.GetNode(node[START_NODE_INDEX].ToString())
.AddEdge(graph.GetNode(node[END_NODE_INDEX].ToString()), Convert.ToInt32(node[EDGE_WEIGHT_INDEX].ToString()));
}
return graph;
}
}
IPathFinder interface
public interface IPathFinder
{
Path GetShortestPath(Node startNode, Node endNode);
List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive);
List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive);
List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight);
List<Path> GetAllPaths(Node startNode, Node endNode);
List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive);
List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive);
List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops);
Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges);
string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges);
}
PathFinder class
public class PathFinder : IPathFinder
{
public string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges)
{
var pathRepresentation = new StringBuilder();
pathRepresentation.AppendFormat("{0}->", startNode.Name);
foreach (var visitedEdge in visiteEdges)
{
if (visitedEdge.TargetNode == endNode)
{
pathRepresentation.Append(endNode.Name);
}
else
{
pathRepresentation.AppendFormat("{0}->", visitedEdge.TargetNode.Name);
}
}
return pathRepresentation.ToString();
}
public Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges)
{
var visitedPaths = visitedEdges as IList<Edge> ?? visitedEdges.ToList();
string pathRepresentation = GetPathRepresentation(startNode, endNode, visitedPaths);
double totalWeight = visitedPaths.Aggregate<Edge, double>(0,
(current, visitedEdge) => current + visitedEdge.Weight);
return new Path(startNode, endNode, pathRepresentation, visitedPaths.Count(), totalWeight);
}
public List<Path> GetAllPaths(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
public Path GetShortestPath(Node startNode, Node endNode)
{
List<Path> paths = GetAllPaths(startNode, endNode);
var shortestPath = new Path();
double shortestPathWeight = double.PositiveInfinity;
if (paths.Count > 0)
{
foreach (var path in paths)
{
if (path.TotalWeight < shortestPathWeight)
{
if (path.TotalWeight < shortestPathWeight)
{
shortestPathWeight = path.TotalWeight;
shortestPath = new Path(startNode, endNode, path.PathRepresentation, path.VisitedCount,
path.TotalWeight);
}
}
}
}
return shortestPath;
}
public List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive)
{
if (inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight >= minWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight > minWeight).ToList();
}
public List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight <= maxWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight < maxWeight).ToList();
}
public List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight)
{
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight.Equals(weight)).ToList();
}
public List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount >= minStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount > minStops).ToList();
}
public List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount <= maxStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount < maxStops).ToList();
}
public List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops)
{
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount == stops).ToList();
}
public List<Path> GetAllPaths2(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
}
IPathPrinter interface
public interface IPathPrinter
{
void PrintShortestPath(Path path);
void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive);
void PrintPathDistance(List<Path> paths);
void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive);
void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops);
}
PathPrinter class
public class PathPrinter : IPathPrinter
{
public void PrintShortestPath(Path path)
{
Console.WriteLine("The shortest path from '{0}' to '{1} is '{2}' with a distance of {3}",
path.StartNode.Name, path.EndNode.Name, path.PathRepresentation, path.TotalWeight);
}
public void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if (inclusive)
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than or equal to {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
else
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
foreach (var path in paths)
{
Console.WriteLine("{0} with a distance of {1}", path.PathRepresentation, path.TotalWeight);
}
}
public void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive)
{
if (inclusive)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
else
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of less than {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
PrintPaths(paths);
}
public void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with exactly {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
PrintPaths(paths);
}
public void PrintPathDistance(List<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine("The distance of the route '{0}' is {1}", path.PathRepresentation, path.TotalWeight);
}
}
private static void PrintPaths(IEnumerable<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine(path.PathRepresentation);
}
}
}
Program class
public class Program
{
public static void Main(string[] args)
{
IPathFinder pathFinder = new PathFinder();
IPathPrinter pathPrinter = new PathPrinter();
IGraph graph = new Graph().CreateGraph();
var pathsAtoC = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->B->C")).ToList());
var pathsAtoD = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("D"));
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->D")).ToList());
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->D->C")).ToList());
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->B->C->D")).ToList());
var validPath = pathsAtoD.Any(x => x.PathRepresentation.Equals("A->E->D"));
if(validPath)
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->D")).ToList());
Console.WriteLine(Environment.NewLine);
var path = pathFinder.GetShortestPath(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
path = pathFinder.GetShortestPath(graph.GetNode("C"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
Console.WriteLine(Environment.NewLine);
var paths = pathFinder.GetPathsWithMaxStops(graph.GetNode("C"), graph.GetNode("C"),3,true);
pathPrinter.PrintPathsWithMaxStops(paths,graph.GetNode("C"),graph.GetNode("C"),3,true);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithExactStops(graph.GetNode("A"), graph.GetNode("C"), 4);
pathPrinter.PrintPathsWithExactStops(paths, graph.GetNode("A"), graph.GetNode("C"), 4);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithMaxWeight(graph.GetNode("C"), graph.GetNode("C"), 30, false);
pathPrinter.PrintPathsWithMaxWeight(paths, graph.GetNode("C"), graph.GetNode("C"), 30,false);
Console.ReadKey();
}
}
Here is my first attempt at refactoring. Instead of using a Tuple
, I used a STRUCT
and this made it more readable. I also extracted printing paths and finding paths into interfaces
so someone could print their own messages or implement there own path finding algorithm. The graph class has a corresponding interface
as well. I am still not sure if I need all the path finding methods, some of them are just one liners, so I wonder if they are necessary. I also want to pass a file name as an args parameter into main, but I am not sure how to get that to my CreateGraph
method. Also, IGraph graph = new Graph().CreateGraph();
seems a bit weird. Is this normal? I am also curious if there is a way to better pass in messages to my PrintXXXPath...
methods, so I don't have to have so many of them?
Node class
Any other refactorings are welcome?
public class Node
{
public string Name { get; private set; }
public List<Edge> Edges { get; private set; }
public Node(string name)
{
Name = name;
Edges = new List<Edge>();
}
public void AddEdge(Node targetNode, double weight)
{
Edges.Add(new Edge(targetNode,weight));
}
}
Edge class
public class Edge
{
public Node TargetNode { get; private set; }
public double Weight { get; private set; }
public Edge(Node targetNode, double weight)
{
TargetNode = targetNode;
Weight = weight;
}
}
QueueItem class
public class QueueItem
{
public Node Node { get; private set; }
public List<Edge> VisitedEdges { get; private set; }
public QueueItem(Node node, List<Edge> visitedEdges)
{
Node = node;
VisitedEdges = visitedEdges;
}
}
Path struct
public struct Path
{
public readonly Node StartNode;
public readonly Node EndNode;
public readonly string PathRepresentation;
public readonly int VisitedCount;
public readonly double TotalWeight;
public Path(Node startNode, Node endNode, string pathRepresentation, int visitedCount, double totalWeight)
{
StartNode = startNode;
EndNode = endNode;
PathRepresentation = pathRepresentation;
VisitedCount = visitedCount;
TotalWeight = totalWeight;
}
}
IGraph interface
public interface IGraph
{
void AddNode(string name);
Node GetNode(string name);
IGraph CreateGraph();
}
Graph class
public class Graph : IGraph
{
public Dictionary<string, Node> Nodes { get; private set; }
public Graph()
{
Nodes = new Dictionary<string, Node>();
}
public void AddNode(string name)
{
Nodes.Add(name, new Node(name));
}
public Node GetNode(string name)
{
if (Nodes.ContainsKey(name))
return Nodes[name];
return null;
}
public IGraph CreateGraph()
{
const int START_NODE_INDEX = 0;
const int END_NODE_INDEX = 1;
const int EDGE_WEIGHT_INDEX = 2;
var nodes = File.ReadAllText("graph.csv").Split(',');
IGraph graph = new Graph();
foreach (var n in nodes)
{
var node = n.Trim();
if (graph.GetNode(node[START_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[START_NODE_INDEX].ToString());
}
if (graph.GetNode(node[END_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[END_NODE_INDEX].ToString());
}
graph.GetNode(node[START_NODE_INDEX].ToString())
.AddEdge(graph.GetNode(node[END_NODE_INDEX].ToString()), Convert.ToInt32(node[EDGE_WEIGHT_INDEX].ToString()));
}
return graph;
}
}
IPathFinder interface
public interface IPathFinder
{
Path GetShortestPath(Node startNode, Node endNode);
List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive);
List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive);
List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight);
List<Path> GetAllPaths(Node startNode, Node endNode);
List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive);
List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive);
List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops);
Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges);
string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges);
}
PathFinder class
public class PathFinder : IPathFinder
{
public string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges)
{
var pathRepresentation = new StringBuilder();
pathRepresentation.AppendFormat("{0}->", startNode.Name);
foreach (var visitedEdge in visiteEdges)
{
if (visitedEdge.TargetNode == endNode)
{
pathRepresentation.Append(endNode.Name);
}
else
{
pathRepresentation.AppendFormat("{0}->", visitedEdge.TargetNode.Name);
}
}
return pathRepresentation.ToString();
}
public Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges)
{
var visitedPaths = visitedEdges as IList<Edge> ?? visitedEdges.ToList();
string pathRepresentation = GetPathRepresentation(startNode, endNode, visitedPaths);
double totalWeight = visitedPaths.Aggregate<Edge, double>(0,
(current, visitedEdge) => current + visitedEdge.Weight);
return new Path(startNode, endNode, pathRepresentation, visitedPaths.Count(), totalWeight);
}
public List<Path> GetAllPaths(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
public Path GetShortestPath(Node startNode, Node endNode)
{
List<Path> paths = GetAllPaths(startNode, endNode);
var shortestPath = new Path();
double shortestPathWeight = double.PositiveInfinity;
if (paths.Count > 0)
{
foreach (var path in paths)
{
if (path.TotalWeight < shortestPathWeight)
{
if (path.TotalWeight < shortestPathWeight)
{
shortestPathWeight = path.TotalWeight;
shortestPath = new Path(startNode, endNode, path.PathRepresentation, path.VisitedCount,
path.TotalWeight);
}
}
}
}
return shortestPath;
}
public List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive)
{
if (inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight >= minWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight > minWeight).ToList();
}
public List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight <= maxWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight < maxWeight).ToList();
}
public List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight)
{
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight.Equals(weight)).ToList();
}
public List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount >= minStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount > minStops).ToList();
}
public List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount <= maxStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount < maxStops).ToList();
}
public List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops)
{
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount == stops).ToList();
}
public List<Path> GetAllPaths2(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
}
IPathPrinter interface
public interface IPathPrinter
{
void PrintShortestPath(Path path);
void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive);
void PrintPathDistance(List<Path> paths);
void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive);
void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops);
}
PathPrinter class
public class PathPrinter : IPathPrinter
{
public void PrintShortestPath(Path path)
{
Console.WriteLine("The shortest path from '{0}' to '{1} is '{2}' with a distance of {3}",
path.StartNode.Name, path.EndNode.Name, path.PathRepresentation, path.TotalWeight);
}
public void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if (inclusive)
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than or equal to {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
else
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
foreach (var path in paths)
{
Console.WriteLine("{0} with a distance of {1}", path.PathRepresentation, path.TotalWeight);
}
}
public void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive)
{
if (inclusive)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
else
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of less than {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
PrintPaths(paths);
}
public void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with exactly {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
PrintPaths(paths);
}
public void PrintPathDistance(List<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine("The distance of the route '{0}' is {1}", path.PathRepresentation, path.TotalWeight);
}
}
private static void PrintPaths(IEnumerable<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine(path.PathRepresentation);
}
}
}
Program class
public class Program
{
public static void Main(string[] args)
{
IPathFinder pathFinder = new PathFinder();
IPathPrinter pathPrinter = new PathPrinter();
IGraph graph = new Graph().CreateGraph();
var pathsAtoC = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->B->C")).ToList());
var pathsAtoD = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("D"));
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->D")).ToList());
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->D->C")).ToList());
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->B->C->D")).ToList());
var validPath = pathsAtoD.Any(x => x.PathRepresentation.Equals("A->E->D"));
if(validPath)
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->D")).ToList());
Console.WriteLine(Environment.NewLine);
var path = pathFinder.GetShortestPath(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
path = pathFinder.GetShortestPath(graph.GetNode("C"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
Console.WriteLine(Environment.NewLine);
var paths = pathFinder.GetPathsWithMaxStops(graph.GetNode("C"), graph.GetNode("C"),3,true);
pathPrinter.PrintPathsWithMaxStops(paths,graph.GetNode("C"),graph.GetNode("C"),3,true);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithExactStops(graph.GetNode("A"), graph.GetNode("C"), 4);
pathPrinter.PrintPathsWithExactStops(paths, graph.GetNode("A"), graph.GetNode("C"), 4);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithMaxWeight(graph.GetNode("C"), graph.GetNode("C"), 30, false);
pathPrinter.PrintPathsWithMaxWeight(paths, graph.GetNode("C"), graph.GetNode("C"), 30,false);
Console.ReadKey();
}
}
Here is my first attempt at refactoring. Instead of using a Tuple
, I used a STRUCT
and this made it more readable. I also extracted printing paths and finding paths into interfaces
so someone could print their own messages or implement there own path finding algorithm. The graph class has a corresponding interface
as well. I am still not sure if I need all the path finding methods, some of them are just one liners, so I wonder if they are necessary. I also want to pass a file name as an args parameter into main, but I am not sure how to get that to my CreateGraph
method. Also, IGraph graph = new Graph().CreateGraph();
seems a bit weird. Is this normal? I am also curious if there is a way to better pass in messages to my PrintXXXPath...
methods, so I don't have to have so many of them?
Node class
Any other refactorings are welcome?
public class Node
{
public string Name { get; private set; }
public List<Edge> Edges { get; private set; }
public Node(string name)
{
Name = name;
Edges = new List<Edge>();
}
public void AddEdge(Node targetNode, double weight)
{
Edges.Add(new Edge(targetNode,weight));
}
}
Edge class
public class Edge
{
public Node TargetNode { get; private set; }
public double Weight { get; private set; }
public Edge(Node targetNode, double weight)
{
TargetNode = targetNode;
Weight = weight;
}
}
QueueItem class
public class QueueItem
{
public Node Node { get; private set; }
public List<Edge> VisitedEdges { get; private set; }
public QueueItem(Node node, List<Edge> visitedEdges)
{
Node = node;
VisitedEdges = visitedEdges;
}
}
Path struct
public struct Path
{
public readonly Node StartNode;
public readonly Node EndNode;
public readonly string PathRepresentation;
public readonly int VisitedCount;
public readonly double TotalWeight;
public Path(Node startNode, Node endNode, string pathRepresentation, int visitedCount, double totalWeight)
{
StartNode = startNode;
EndNode = endNode;
PathRepresentation = pathRepresentation;
VisitedCount = visitedCount;
TotalWeight = totalWeight;
}
}
IGraph interface
public interface IGraph
{
void AddNode(string name);
Node GetNode(string name);
IGraph CreateGraph();
}
Graph class
public class Graph : IGraph
{
public Dictionary<string, Node> Nodes { get; private set; }
public Graph()
{
Nodes = new Dictionary<string, Node>();
}
public void AddNode(string name)
{
Nodes.Add(name, new Node(name));
}
public Node GetNode(string name)
{
if (Nodes.ContainsKey(name))
return Nodes[name];
return null;
}
public IGraph CreateGraph()
{
const int START_NODE_INDEX = 0;
const int END_NODE_INDEX = 1;
const int EDGE_WEIGHT_INDEX = 2;
var nodes = File.ReadAllText("graph.csv").Split(',');
IGraph graph = new Graph();
foreach (var n in nodes)
{
var node = n.Trim();
if (graph.GetNode(node[START_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[START_NODE_INDEX].ToString());
}
if (graph.GetNode(node[END_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[END_NODE_INDEX].ToString());
}
graph.GetNode(node[START_NODE_INDEX].ToString())
.AddEdge(graph.GetNode(node[END_NODE_INDEX].ToString()), Convert.ToInt32(node[EDGE_WEIGHT_INDEX].ToString()));
}
return graph;
}
}
IPathFinder interface
public interface IPathFinder
{
Path GetShortestPath(Node startNode, Node endNode);
List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive);
List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive);
List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight);
List<Path> GetAllPaths(Node startNode, Node endNode);
List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive);
List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive);
List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops);
Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges);
string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges);
}
PathFinder class
public class PathFinder : IPathFinder
{
public string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges)
{
var pathRepresentation = new StringBuilder();
pathRepresentation.AppendFormat("{0}->", startNode.Name);
foreach (var visitedEdge in visiteEdges)
{
if (visitedEdge.TargetNode == endNode)
{
pathRepresentation.Append(endNode.Name);
}
else
{
pathRepresentation.AppendFormat("{0}->", visitedEdge.TargetNode.Name);
}
}
return pathRepresentation.ToString();
}
public Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges)
{
var visitedPaths = visitedEdges as IList<Edge> ?? visitedEdges.ToList();
string pathRepresentation = GetPathRepresentation(startNode, endNode, visitedPaths);
double totalWeight = visitedPaths.Aggregate<Edge, double>(0,
(current, visitedEdge) => current + visitedEdge.Weight);
return new Path(startNode, endNode, pathRepresentation, visitedPaths.Count(), totalWeight);
}
public List<Path> GetAllPaths(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
public Path GetShortestPath(Node startNode, Node endNode)
{
List<Path> paths = GetAllPaths(startNode, endNode);
var shortestPath = new Path();
double shortestPathWeight = double.PositiveInfinity;
if (paths.Count > 0)
{
foreach (var path in paths)
{
if (path.TotalWeight < shortestPathWeight)
{
if (path.TotalWeight < shortestPathWeight)
{
shortestPathWeight = path.TotalWeight;
shortestPath = new Path(startNode, endNode, path.PathRepresentation, path.VisitedCount,
path.TotalWeight);
}
}
}
}
return shortestPath;
}
public List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive)
{
if (inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight >= minWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight > minWeight).ToList();
}
public List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight <= maxWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight < maxWeight).ToList();
}
public List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight)
{
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight.Equals(weight)).ToList();
}
public List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount >= minStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount > minStops).ToList();
}
public List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount <= maxStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount < maxStops).ToList();
}
public List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops)
{
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount == stops).ToList();
}
public List<Path> GetAllPaths2(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
}
IPathPrinter interface
public interface IPathPrinter
{
void PrintShortestPath(Path path);
void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive);
void PrintPathDistance(List<Path> paths);
void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive);
void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops);
}
PathPrinter class
public class PathPrinter : IPathPrinter
{
public void PrintShortestPath(Path path)
{
Console.WriteLine("The shortest path from '{0}' to '{1} is '{2}' with a distance of {3}",
path.StartNode.Name, path.EndNode.Name, path.PathRepresentation, path.TotalWeight);
}
public void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if (inclusive)
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than or equal to {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
else
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
foreach (var path in paths)
{
Console.WriteLine("{0} with a distance of {1}", path.PathRepresentation, path.TotalWeight);
}
}
public void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive)
{
if (inclusive)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
else
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of less than {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
PrintPaths(paths);
}
public void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with exactly {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
PrintPaths(paths);
}
public void PrintPathDistance(List<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine("The distance of the route '{0}' is {1}", path.PathRepresentation, path.TotalWeight);
}
}
private static void PrintPaths(IEnumerable<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine(path.PathRepresentation);
}
}
}
Program class
public class Program
{
public static void Main(string[] args)
{
IPathFinder pathFinder = new PathFinder();
IPathPrinter pathPrinter = new PathPrinter();
IGraph graph = new Graph().CreateGraph();
var pathsAtoC = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->B->C")).ToList());
var pathsAtoD = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("D"));
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->D")).ToList());
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->D->C")).ToList());
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->B->C->D")).ToList());
var validPath = pathsAtoD.Any(x => x.PathRepresentation.Equals("A->E->D"));
if(validPath)
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->D")).ToList());
Console.WriteLine(Environment.NewLine);
var path = pathFinder.GetShortestPath(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
path = pathFinder.GetShortestPath(graph.GetNode("C"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
Console.WriteLine(Environment.NewLine);
var paths = pathFinder.GetPathsWithMaxStops(graph.GetNode("C"), graph.GetNode("C"),3,true);
pathPrinter.PrintPathsWithMaxStops(paths,graph.GetNode("C"),graph.GetNode("C"),3,true);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithExactStops(graph.GetNode("A"), graph.GetNode("C"), 4);
pathPrinter.PrintPathsWithExactStops(paths, graph.GetNode("A"), graph.GetNode("C"), 4);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithMaxWeight(graph.GetNode("C"), graph.GetNode("C"), 30, false);
pathPrinter.PrintPathsWithMaxWeight(paths, graph.GetNode("C"), graph.GetNode("C"), 30,false);
Console.ReadKey();
}
}
Here is my first attempt at refactoring. Instead of using a Tuple
, I used a STRUCT
and this made it more readable. I also extracted printing paths and finding paths into interfaces
so someone could print their own messages or implement there own path finding algorithm. The graph class has a corresponding interface
as well. I am still not sure if I need all the path finding methods, some of them are just one liners, so I wonder if they are necessary. I also want to pass a file name as an args parameter into main, but I am not sure how to get that to my CreateGraph
method. Also, IGraph graph = new Graph().CreateGraph();
seems a bit weird. Is this normal? I am also curious if there is a way to better pass in messages to my PrintXXXPath...
methods, so I don't have to have so many of them?
Node class
Any other refactorings are welcome?
public class Node
{
public string Name { get; private set; }
public List<Edge> Edges { get; private set; }
public Node(string name)
{
Name = name;
Edges = new List<Edge>();
}
public void AddEdge(Node targetNode, double weight)
{
Edges.Add(new Edge(targetNode,weight));
}
}
Edge class
public class Edge
{
public Node TargetNode { get; private set; }
public double Weight { get; private set; }
public Edge(Node targetNode, double weight)
{
TargetNode = targetNode;
Weight = weight;
}
}
QueueItem class
public class QueueItem
{
public Node Node { get; private set; }
public List<Edge> VisitedEdges { get; private set; }
public QueueItem(Node node, List<Edge> visitedEdges)
{
Node = node;
VisitedEdges = visitedEdges;
}
}
Path struct
public struct Path
{
public readonly Node StartNode;
public readonly Node EndNode;
public readonly string PathRepresentation;
public readonly int VisitedCount;
public readonly double TotalWeight;
public Path(Node startNode, Node endNode, string pathRepresentation, int visitedCount, double totalWeight)
{
StartNode = startNode;
EndNode = endNode;
PathRepresentation = pathRepresentation;
VisitedCount = visitedCount;
TotalWeight = totalWeight;
}
}
IGraph interface
public interface IGraph
{
void AddNode(string name);
Node GetNode(string name);
IGraph CreateGraph();
}
Graph class
public class Graph : IGraph
{
public Dictionary<string, Node> Nodes { get; private set; }
public Graph()
{
Nodes = new Dictionary<string, Node>();
}
public void AddNode(string name)
{
Nodes.Add(name, new Node(name));
}
public Node GetNode(string name)
{
if (Nodes.ContainsKey(name))
return Nodes[name];
return null;
}
public IGraph CreateGraph()
{
const int START_NODE_INDEX = 0;
const int END_NODE_INDEX = 1;
const int EDGE_WEIGHT_INDEX = 2;
var nodes = File.ReadAllText("graph.csv").Split(',');
IGraph graph = new Graph();
foreach (var n in nodes)
{
var node = n.Trim();
if (graph.GetNode(node[START_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[START_NODE_INDEX].ToString());
}
if (graph.GetNode(node[END_NODE_INDEX].ToString()) == null)
{
graph.AddNode(node[END_NODE_INDEX].ToString());
}
graph.GetNode(node[START_NODE_INDEX].ToString())
.AddEdge(graph.GetNode(node[END_NODE_INDEX].ToString()), Convert.ToInt32(node[EDGE_WEIGHT_INDEX].ToString()));
}
return graph;
}
}
IPathFinder interface
public interface IPathFinder
{
Path GetShortestPath(Node startNode, Node endNode);
List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive);
List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive);
List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight);
List<Path> GetAllPaths(Node startNode, Node endNode);
List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive);
List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive);
List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops);
Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges);
string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges);
}
PathFinder class
public class PathFinder : IPathFinder
{
public string GetPathRepresentation(Node startNode, Node endNode, IEnumerable<Edge> visiteEdges)
{
var pathRepresentation = new StringBuilder();
pathRepresentation.AppendFormat("{0}->", startNode.Name);
foreach (var visitedEdge in visiteEdges)
{
if (visitedEdge.TargetNode == endNode)
{
pathRepresentation.Append(endNode.Name);
}
else
{
pathRepresentation.AppendFormat("{0}->", visitedEdge.TargetNode.Name);
}
}
return pathRepresentation.ToString();
}
public Path GetPath(Node startNode, Node endNode, IEnumerable<Edge> visitedEdges)
{
var visitedPaths = visitedEdges as IList<Edge> ?? visitedEdges.ToList();
string pathRepresentation = GetPathRepresentation(startNode, endNode, visitedPaths);
double totalWeight = visitedPaths.Aggregate<Edge, double>(0,
(current, visitedEdge) => current + visitedEdge.Weight);
return new Path(startNode, endNode, pathRepresentation, visitedPaths.Count(), totalWeight);
}
public List<Path> GetAllPaths(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
public Path GetShortestPath(Node startNode, Node endNode)
{
List<Path> paths = GetAllPaths(startNode, endNode);
var shortestPath = new Path();
double shortestPathWeight = double.PositiveInfinity;
if (paths.Count > 0)
{
foreach (var path in paths)
{
if (path.TotalWeight < shortestPathWeight)
{
if (path.TotalWeight < shortestPathWeight)
{
shortestPathWeight = path.TotalWeight;
shortestPath = new Path(startNode, endNode, path.PathRepresentation, path.VisitedCount,
path.TotalWeight);
}
}
}
}
return shortestPath;
}
public List<Path> GetPathsWithMinWeight(Node startNode, Node endNode, double minWeight, bool inclusive)
{
if (inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight >= minWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight > minWeight).ToList();
}
public List<Path> GetPathsWithMaxWeight(Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight <= maxWeight).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight < maxWeight).ToList();
}
public List<Path> GetPathsWithExactWeight(Node startNode, Node endNode, double weight)
{
return GetAllPaths(startNode, endNode).Where(path => path.TotalWeight.Equals(weight)).ToList();
}
public List<Path> GetPathsWithMinStops(Node startNode, Node endNode, int minStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount >= minStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount > minStops).ToList();
}
public List<Path> GetPathsWithMaxStops(Node startNode, Node endNode, int maxStops, bool inclusive)
{
if(inclusive)
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount <= maxStops).ToList();
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount < maxStops).ToList();
}
public List<Path> GetPathsWithExactStops(Node startNode, Node endNode, int stops)
{
return GetAllPaths(startNode, endNode).Where(path => path.VisitedCount == stops).ToList();
}
public List<Path> GetAllPaths2(Node startNode, Node endNode)
{
var paths = new List<Path>();
var queue = new Queue<QueueItem>();
queue.Enqueue(new QueueItem(startNode, new List<Edge>()));
while (queue.Count > 0)
{
var currentItem = queue.Dequeue();
foreach (var edge in currentItem.Node.Edges)
{
if (!currentItem.VisitedEdges.Contains(edge))
{
var visitedEdges = new List<Edge>(currentItem.VisitedEdges) { edge };
if (edge.TargetNode == endNode)
{
var path = GetPath(startNode, endNode, visitedEdges);
paths.Add(path);
}
else
{
queue.Enqueue(new QueueItem(edge.TargetNode, visitedEdges));
}
}
}
}
return paths;
}
}
IPathPrinter interface
public interface IPathPrinter
{
void PrintShortestPath(Path path);
void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive);
void PrintPathDistance(List<Path> paths);
void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive);
void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops);
}
PathPrinter class
public class PathPrinter : IPathPrinter
{
public void PrintShortestPath(Path path)
{
Console.WriteLine("The shortest path from '{0}' to '{1} is '{2}' with a distance of {3}",
path.StartNode.Name, path.EndNode.Name, path.PathRepresentation, path.TotalWeight);
}
public void PrintPathsWithMaxWeight(List<Path> paths, Node startNode, Node endNode, double maxWeight, bool inclusive)
{
if (inclusive)
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than or equal to {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
else
{
Console.WriteLine(
"The number of trips from '{0}' to '{1}' with a distance of less than {2} is {3}:",
startNode.Name, endNode.Name, maxWeight, paths.Count);
}
foreach (var path in paths)
{
Console.WriteLine("{0} with a distance of {1}", path.PathRepresentation, path.TotalWeight);
}
}
public void PrintPathsWithMaxStops(List<Path> paths, Node startNode, Node endNode, int maxStops, bool inclusive)
{
if (inclusive)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
else
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with a maximum of less than {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
}
PrintPaths(paths);
}
public void PrintPathsWithExactStops(List<Path> paths, Node startNode, Node endNode, int maxStops)
{
Console.WriteLine("The number of trips from '{0}' to '{1}' with exactly {2} stops is {3}:", startNode.Name, endNode.Name, maxStops, paths.Count);
PrintPaths(paths);
}
public void PrintPathDistance(List<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine("The distance of the route '{0}' is {1}", path.PathRepresentation, path.TotalWeight);
}
}
private static void PrintPaths(IEnumerable<Path> paths)
{
foreach (var path in paths)
{
Console.WriteLine(path.PathRepresentation);
}
}
}
Program class
public class Program
{
public static void Main(string[] args)
{
IPathFinder pathFinder = new PathFinder();
IPathPrinter pathPrinter = new PathPrinter();
IGraph graph = new Graph().CreateGraph();
var pathsAtoC = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->B->C")).ToList());
var pathsAtoD = pathFinder.GetAllPaths(graph.GetNode("A"), graph.GetNode("D"));
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->D")).ToList());
pathPrinter.PrintPathDistance(pathsAtoC.Where(x => x.PathRepresentation.Equals("A->D->C")).ToList());
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->B->C->D")).ToList());
var validPath = pathsAtoD.Any(x => x.PathRepresentation.Equals("A->E->D"));
if(validPath)
pathPrinter.PrintPathDistance(pathsAtoD.Where(x => x.PathRepresentation.Equals("A->E->D")).ToList());
Console.WriteLine(Environment.NewLine);
var path = pathFinder.GetShortestPath(graph.GetNode("A"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
path = pathFinder.GetShortestPath(graph.GetNode("C"), graph.GetNode("C"));
pathPrinter.PrintShortestPath(path);
Console.WriteLine(Environment.NewLine);
var paths = pathFinder.GetPathsWithMaxStops(graph.GetNode("C"), graph.GetNode("C"),3,true);
pathPrinter.PrintPathsWithMaxStops(paths,graph.GetNode("C"),graph.GetNode("C"),3,true);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithExactStops(graph.GetNode("A"), graph.GetNode("C"), 4);
pathPrinter.PrintPathsWithExactStops(paths, graph.GetNode("A"), graph.GetNode("C"), 4);
Console.WriteLine(Environment.NewLine);
paths = pathFinder.GetPathsWithMaxWeight(graph.GetNode("C"), graph.GetNode("C"), 30, false);
pathPrinter.PrintPathsWithMaxWeight(paths, graph.GetNode("C"), graph.GetNode("C"), 30,false);
Console.ReadKey();
}
}