First time working with any type of graph traversal. The algorithm determines whether a path exists between two nodes using breadth first searching (BFS). The BFS method returns a tuple; indicating whether a match has been found and the length between the two nodes. I implemented it this way since it's part of a private member and wont be seen externally. When the result is seen as part of the HasPath
method I modeled it after the Try-Pattern similar to TryParse(...)
.
The local function EnqueueNonVisitedChildrenNodes
is declared as such since it would make no sense to call it anywhere else. It too uses a tuple to simplify its invocation.
Am I properly using the tuple type? Is there anything that could be improved with code structure?
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Name = {Name}, ChildCount = {Children.Count}")]
public class Node
{
public string Name { get; }
public List<Node> Children { get; } = new List<Node>();
public bool Visited { get; set; }
public Node(string Name)
{
this.Name = Name;
}
public Node(string name, IEnumerable<Node> children)
{
Name = name;
foreach (var node in children)
{
AddChild(node);
}
}
public void AddChild(Node node)
{
Children.Add(node);
}
}
The implemented algorithm.
public class PathAlgorithm
{
Node Start { get; }
Node End { get; }
public PathAlgorithm(Node start, Node end)
{
Start = start ?? throw new ArgumentNullException(nameof(start));
End = end ?? throw new ArgumentNullException(nameof(end));
}
public bool HasPath(out int length)
{
bool hasPath;
(hasPath, length) = BreadthFirstSearch(Start);
return hasPath;
}
public (bool, int) BreadthFirstSearch(Node root)
{
if (root == null)
{
return (false, 0);
}
Queue<(Node, int)> searchQueue = new Queue<(Node, int)>();
root.Visited = true;
searchQueue.Enqueue((root, 0));
while (searchQueue.Any())
{
(Node node, int length) = searchQueue.Dequeue();
if (node == End)
{
return (true, length);
}
EnqueueNonVisitedChildrenNodes(searchQueue, (node, length));
}
return (false, 0);
void EnqueueNonVisitedChildrenNodes(Queue<(Node, int)> queue, (Node node, int length) foo)
{
foreach (var n in foo.node.Children)
{
if (!n.Visited)
{
n.Visited = true;
searchQueue.Enqueue((n, foo.length + 1));
}
}
}
}
}