I have been trying to write a function to find the shortest path, implementing the AStar algorithm. I have gone through many solutions on net and on this forum. But my bad, I am having a tough time understanding where exactly I need to 'remove the node from the path' if the path did not hit the destination. Infact the adding and removing nodes as we go along a path and as we come back after reaching a dead-end in the recursion, seemed a bit challenging to understand. At the end of the recursion, if the path is not found, I am clearing the path and returning it, which I know is not the way to implement. However, I am sharing the code here. Could someone kindly help me understand what I am doing wrong?
Here is the Node class;
public class Node
{
public string Name { get; private set; }
public Coordinate Location { get; private set; }
public double g { get; set; }
public double h { get; set; }
public double cost { get { return this.g + this.h; } }
public List<Node> Neighbours { get; set; }
public Node(string name, Coordinate location)
{
Name = name;
Location = location;
Neighbours= new List<Node>();
}
public void AddNeighbours(List<Node> neighbours)
{
Neighbours.AddRange(neighbours);
}
public double distanceTo(Node node)
{
return Location.Distance(node.Location);
}
}
...and here is the Graph class.
public class Graph
{
List<Node> Nodes = new List<Node>();
public Graph(List<Node> nodes)
{
Nodes = nodes;
}
public List<Node> GetShortestPath(Node source, Node destination, HashSet<Node> visited = null, List<Node> path = null )
{
if ( visited == null ) { visited = new HashSet<Node>(); } // Initialize the visited nodes list
if(path == null ) { path = new List<Node>() {}; } // initialize the shortest path list
if (source == destination){ path.Add(destination); return path;}
visited.Add(source); // Currently visiting this node. So, add to the visited nodes
path.Add(source); // Add the current source to the path
foreach (Node neighbour in source.Neighbours) // for each neighbour node
{
// Update the g and h distances
neighbour.g = source.g + source.distanceTo(neighbour);
neighbour.h = neighbour.distanceTo(destination);
}
// Collect the non-visited neighbours
List<Node> nonVisitedNeighbours = source.Neighbours.Where(n => !visited.Contains(n)).ToList();
if (nonVisitedNeighbours.Count > 0) // if non-visited neighbours not empty
{
// sort the neighbours in ascending order and take the first one.
// that will be the closest neighbour with the lowest cost
Node nextNeighbour = nonVisitedNeighbours.OrderBy(n => n.cost).ToList().First();
return GetShortestPath(nextNeighbour, destination, visited, path);
}
path.Clear(); // I hope this is not the right way, but somewhere path.Remove(source) to be added. But not clear where...
Console.WriteLine("No path found!");
return path; // This should return an empty list
}
}
Ok... I fixed it. Here is the final implementation...
public List<Node> GetPath(
Node startNode,
Node targetNode
)
{
List<Node> openSet = new List<Node>();
HashSet<Node> closedSet = new HashSet<Node>();
openSet.Add(startNode);
while (openSet.Count > 0)
{
Node currentNode = openSet[0];
List<Node> nodesWithLesserCost = openSet
.Skip(1)
.ToList()
.Where(node => node.Cost < currentNode.Cost || node.Cost == currentNode.Cost && node.H < currentNode.H)
.OrderBy(n => n.Cost)
.ToList();
if (nodesWithLesserCost.Any())
{
currentNode = nodesWithLesserCost.First();
}
openSet.Remove(currentNode);
closedSet.Add(currentNode);
if (currentNode == targetNode)
{
return RetracePath(startNode, targetNode);
}
foreach (Node neighbour in currentNode.Neighbours)
{
if (closedSet.Contains(neighbour))
{
continue;
}
double newMovementCostToNeighbour = currentNode.G + currentNode.DistanceTo(neighbour);
if(newMovementCostToNeighbour < neighbour.G || !openSet.Contains(neighbour))
{
neighbour.G = newMovementCostToNeighbour;
neighbour.H = neighbour.DistanceTo(targetNode);
neighbour.Parent = currentNode;
if (!openSet.Contains(neighbour))
{
openSet.Add(neighbour);
}
}
}
}
Console.WriteLine("No Path Found...!");
return new List<Node>();
}
Related
Can I find non-binary tree depth.
Every node can have multiple children. We don't know how much is the maximum count of nodes.
public class Node
{
private List<Node> nodes;
private string nodeName;
public Node(string nodeName)
{
nodes = new List<Node>();
this.nodeName = nodeName;
}
public List<Node> Nodes
{
get { return this.nodes; }
set { this.nodes = value; }
}
protected string NodeName
{
get { return this.nodeName; }
}
}
You can do something like this to calculate the maximum depth (including the root node):
public static int Depth(Node root, int depth)
{
int result = depth + 1;
foreach (var node in root.Nodes)
result = Math.Max(result, Depth(node, depth + 1));
return result;
}
You would call it passing in 0 for the initial depth:
int depth = Depth(root, 0);
If you just want to count ALL the nodes rather than the depth:
public static int CountExcludingRoot(Node root)
{
return root.Nodes.Sum(node => 1 + CountExcludingRoot(node));
}
(This excludes the root node, so you need to add one to the value returned to get the total of all nodes including the root).
Title may be misleading as I had some trouble searching and even creating a proper question, so let me give a real problem I'm struggling with:
I have a Graph class. Since graphs need nodes and edges I created two additional classes Node (vertex) and Edge. My structure looks like this:
class Graph
{
List<Node> nodes;
List<Edge> edges;
public Graph( ... ) { /* populate lists */ }
}
class Node { ... }
class Edge { ... }
I wrote some methods for Node class, one is particularly problematic for me. Signature:
public List<Node> GetNeighbours(List<Edge> edges) { ... }
Pretty standard. Given a graph I ask a node: how many neighbours do you have? I need list of edges to resolve it.
How can I refactor this code so that I can use Graph properties/fields inside instead of passing a list of edges every time? Is something like this possible:
public List<Node> GetNeighbours()
{
// ...
foreach(edge in *BASE*.edges) { ... }
}
I know that I can't use the base keyword because I don't want any inheritance here (why would a node have to inherit from graph?!) and nested classes seem not to help me as well (no access to "parent's" fields).
This code is working right now, but I feel it's not elegant and I'd like to experience a proper solution.
Pass a reference to the parent class in the Graph constructor.
Something like:
class Graph
{
private ParentType parent;
public void Graph(ref ParentType parent)
{
this.parent = parent;
}
}
Then, in the GetNeighbours method (assuming the ParentType has an Edges collection property):
public List<Node> GetNeighbours()
{
// ...
foreach(var edge in parent.Edges) { ... }
}
From this description of what you're trying to do:
Given a graph I ask a node: how many neighbours do you have?
Are you sure that this should be a method of a Node? Since Graph contains the Nodes and Edges perhaps this method is better off in Graph.
public List<Node> GetNeighbours(Node node)
{
if(!nodes.Contains(node)
{
return new List<Node>(); //No neighbors. Return an empty list.
}
// Find and return the neighbors. This method is in Graph so it
// has access to all of Graph's internals.
}
My reasoning is that since in a sense Graph is a parent and it contains Nodes, Node does not need to know about Graph. Its purpose (Single Responsibility) is complete without any references to Graph.
I would have a method like Graph.AddNodes() or Graph.AddEdges() on Graph so that this is a central place to make sure that all Nodes (and/or Edges) have the reference that it needs. I'm thinking something like this, depending on the model of Node and Edge for you.
class Graph
{
List<Node> nodes;
List<Edge> edges;
public Graph( ... ) { /* populate lists */ }
public void AddEdges(params Edge[] edges) {
foreach (var edge in edges) {
edge.Node1.Parent = this;
edge.Node2.Parent = this;
}
}
}
class Node {
public Graph Parent { get; set; }
public List<Node> GetNeighbours()
{
var neighbors = new List<Node>();
foreach(var edge in parent.Edges) {
if (edge.Node1 == this && !neighbors.Contains(edge.Node2)) {
neighbors.Add(edge.Node2);
}
else if (edge.Node2 == this && !neighbors.Contains(edge.Node1)) {
neighbors.Add(edge.Node1);
}
}
}
}
class Edge {
public Node Node1 { get; set; }
public Node Node2 { get; set; }
}
Here is an alternative approach. Instead of passing the parent reference, you could make each edge aware of the nodes on each end. And make each node aware of the edges connected to them.
A massive advantage of this is that you do not need enumerate possibly massive amounts of nodes/edges to find what you need. You already have what you need so it is much faster.
Here is quick sample of the approach I described along with some tests:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GraphModelTest
{
class Program
{
static void Main(string[] args)
{
TestA();
TestB();
TestC();
}
private static void TestC()
{
//A <-> B
//| |
//D <-> C
Node a = new Node("a");
Node b = new Node("b");
Node c = new Node("c");
Node d = new Node("d");
Edge ab = a.ConnectTo(b);
Edge bc = b.ConnectTo(c);
Edge cd = c.ConnectTo(d);
Edge da = d.ConnectTo(a);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Nodes.Add(c);
g.Nodes.Add(d);
g.Edges.Add(ab);
g.Edges.Add(bc);
g.Edges.Add(cd);
g.Edges.Add(da);
Console.WriteLine(g.ToString());
Console.WriteLine("Neighbours of B");
foreach (Node n in b.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
Console.WriteLine("Neighbours of D");
foreach (Node n in d.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
}
private static void TestB()
{
//A <-> B <-> C
Node a = new Node("a");
Node b = new Node("b");
Edge ab = a.ConnectTo(b);
Node c = new Node("c");
Edge bc = b.ConnectTo(c);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Nodes.Add(c);
g.Edges.Add(ab);
g.Edges.Add(bc);
Console.WriteLine(g.ToString());
Console.WriteLine("Neighbours of B");
foreach (Node n in b.GetNeighbours())
{
Console.WriteLine(n.ToString());
}
}
private static void TestA()
{
//A <-> B
Node a = new Node("a");
Node b = new Node("b");
Edge ab = a.ConnectTo(b);
Graph g = new Graph();
g.Nodes.Add(a);
g.Nodes.Add(b);
g.Edges.Add(ab);
Console.WriteLine(g.ToString());
}
}
class Edge
{
public Edge(string name, Node a, Node b)
{
Name = name;
A = a;
B = b;
}
public Node A { get; private set; }
public Node B { get; private set; }
public string Name { get; private set; }
public override string ToString() => $"{Name}";
}
class Node
{
public Node(string name)
{
Name = name;
connectedEdges = new List<Edge>();
}
public string Name { get; private set; }
private ICollection<Edge> connectedEdges;
public IEnumerable<Edge> ConnectedEdges
{
get
{
return connectedEdges.AsEnumerable();
}
}
public void AddConnectedEdge(Edge e)
{
connectedEdges.Add(e);
}
public Edge ConnectTo(Node n)
{
//Create the edge with references to nodes
Edge e = new Edge($"{Name} <-> {n.Name}", this, n);
//Add edge reference to this node
AddConnectedEdge(e);
//Add edge reference to the other node
n.AddConnectedEdge(e);
return e;
}
public IEnumerable<Node> GetNeighbours()
{
foreach (Edge e in ConnectedEdges)
{
//Have to figure which one is not this node
Node node = e.A != this ? e.A : e.B;
yield return node;
}
}
public override string ToString() => $"{Name}";
}
class Graph
{
public Graph()
{
Nodes = new List<Node>();
Edges = new List<Edge>();
}
public ICollection<Node> Nodes { get; set; }
public ICollection<Edge> Edges { get; set; }
public override string ToString()
{
StringBuilder str = new StringBuilder();
str.AppendLine("Graph:");
str.AppendLine("Nodes:");
foreach (Node n in Nodes)
{
str.AppendLine(n.ToString());
}
str.AppendLine("Edges:");
foreach (Edge e in Edges)
{
str.AppendLine(e.ToString());
}
return str.ToString();
}
}
}
I have a node class that contains only value type properties, and one reference type: it's parent node. When performing tree searches, these nodes are created and destroyed hundreds of thousands of times in a very short time span.
public class Node
{
public Node Parent { get; set; }
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public int D { get; set; }
}
The tree search looks something like this:
public static Node GetDepthFirstBest(this ITree tree, Node root)
{
Node bestNode = root;
float bestScore = tree.Evaluate(root);
var stack = new Stack<Node>();
stack.Push(root);
while(stack.Count > 0)
{
var current = stack.Pop();
float score = tree.Evaluate(current);
if (score > bestScore)
{
bestNode = current;
bestScore = score;
}
var children = tree.GetChildren(current);
foreach(var c in children) { stack.Push(c); }
}
return bestNode;
}
Because this is done in a Mono runtime that has a very old GC, I wanted to try and pool the node objects. However, I am at a loss on how to know when a node object is safe to return to the pool, since other nodes that are still in use might reference it as a parent. At the end of the search, the best node is returned and a list of nodes is formed by walking back through its ancestors. I have full control over how the nodes are created inside the tree, if that's useful.
What options could I try and implement?
So, fortunately, if you're doing a Depth-First-Search, which you appear to be, this is a bit easier. Any time you reach a leaf node, there are two possibilities: that leaf node is part of the current deepest tree, or it's not.
If it's not, that means it's safe to return this node to the pool. If it is, that means we can return any nodes in our old tree back to our pool that are not in our own ancestor chain.
Now, if we're not a leafnode, we don't know if we can be freed until after we've finished checking our children. then, once all our children are checked, we find out if any of our children said they were the current best. if so, we keep ourselves
this does mean we're doing quite a bit more checking.
Here's some sudo code:
List bestNodes;
bool evalNode(node, score)
{
if (childCount == 0)
{
if (score > bestScore)
{
bestScore = score;
bestNode = node;
bestNodes.Add(node);
return true;
}
else
{
freeNode(this);
return false;
}
}
else
{
bool inLongest = false;
foreach (child in children)
{
inLongest = evalNode(child, score + 1) || inLongest;
}
if (!inLongest)
{
freeNode(node);
}
else
{
free(bestNodes[score]);
bestNodes[score] = node;
}
return inLongest;
}
}
Try using the ref keyword if your node is a struct, this avoids copying the node every time you pass it through to a function.
Thus:
struct Node
{
object obj;
Node children;
}
public void DoStuffWithNode(ref Node pNode){...Logic...}
I want to create a treeview in c# which will group file by prefix (here the prefix is a marked by the separator _). The following files should give this tree:
Files list :
p_a
p_a_test
p_LIG
p_p
p_p_c
p_p_c2
p_p_ccc
p_p_test
p_tres
TestLineGraph1
TestLineGrpah
Corresponding tree:
|--p_
|--p_a
|--p_a_test
|--p_LIG
|--p_p
|--p_p_
|--p_p_c
|--p_p_c2
|--p_p_ccc
|--p_p_test
|--p_tres
TestLineGraph1
TestLineGrpah
Here's my attempt of code:
private GraphUINode(List<string> subNodes, GraphUINode parent, string name, int lvl = 0)
: base(parent.m_viewDataSubControl)
{
parent.Nodes.Add(this);
this.Name = name;
this.Text = name;
string currentPrefix = "";
int pertinentSubNodes = 0;
while (pertinentSubNodes < subNodes.Count -1 && subNodes[pertinentSubNodes].Split('_').Length < 2+ lvl)
pertinentSubNodes++;
for (int i = 0; i <= lvl; i++)
{
currentPrefix += subNodes[pertinentSubNodes].Split('_')[i] + "_";
}
List<String> children = new List<string>();
foreach (string child in subNodes)
{
// The child is in the same group than the previous one
if (child.StartsWith(currentPrefix))
{
children.Add(child);
}
else
{
// Create a node only if needed
if (children.Count > 1)
{
// Create the new node
new GraphUINode(children, this, currentPrefix, lvl + 1);
children.Clear();
children.Add(child);
}
else
{
new GraphTemplateNode(this, m_viewDataSubControl, child);
}
currentPrefix = "";
for (int i = 0; i <= lvl; i++)
{
currentPrefix += child.Split('_')[i] + "_";
}
}
}
}
But I miss a few ones in the final result:
How can I get its back? Even when I debug step by step I can't find the logical way to do it.
So the first thing that we'll want to do here is take our strings and turn them into a tree. Once we have a tree then mapping those nodes to a TreeView is quite easy.
We'll start out with the definition for the tree itself:
public class Node<T>
{
public Node(T value, IEnumerable<Node<T>> children)
{
Value = value;
Children = children;
}
public T Value { get; private set; }
public IEnumerable<Node<T>> Children { get; private set; }
}
Nice and easy, each node is just a value and a collection of children.
Next we'll write a method to take a sequence of sequences, and build a tree from it. The idea here is that we'll group all of the items based on the first value in their sequence, build a node for each group, and then recursively call the method on the group to get the children for that node.
public static IList<Node<T>> GroupToTree<T>(this IEnumerable<IEnumerable<T>> source)
{
return GroupToTree(source.Select(sequence => sequence.GetEnumerator()));
}
private static IList<Node<T>> GroupToTree<T>(IEnumerable<IEnumerator<T>> source)
{
return source.WhereHasNext()
.GroupBy(iterator => iterator.Current)
.Select(group => new Node<T>(group.Key, GroupToTree(group)))
.ToList();
}
//This ensures that the iterators all get disposed
private static IEnumerable<IEnumerator<T>> WhereHasNext<T>(
this IEnumerable<IEnumerator<T>> source)
{
foreach (var iterator in source)
{
if (iterator.MoveNext())
yield return iterator;
else
iterator.Dispose();
}
}
Now we can take the raw data, split each of the strings into sequences of strings, and then map each of the nodes that we have here into UI-based nodes for presentation:
List<string> rawData = new List<string>();
//TODO populate raw data
Func<Node<string>, TreeNode> selector = null;
selector = node => new TreeNode(node.Value, node.Children.Select(selector).ToArray());
var nodes = rawData.Select(line => line.Split('_').AsEnumerable())
.GroupToTree()
.Select(selector);
Classes:
public class Tree
{
public Node RootNode { get; set; }
}
public class Node
{
public int Key { get; set; }
public object Value { get; set; }
public Node ParentNode { get; set; }
public List<Node> Nodes { get; set; }
}
Methods:
This method generates a tree.
private static int totalNodes = 0;
static Tree GenerateTree()
{
Tree t = new Tree();
t.RootNode = new Node();
t.RootNode.Key = 0;
t.RootNode.Nodes = new List<Node>();
Console.WriteLine(t.RootNode.Key);
List<Node> rootNodes = new List<Node>();
rootNodes.Add(t.RootNode);
while (totalNodes <= 100000)
{
List<Node> newRootNodes = new List<Node>();
foreach (var rootNode in rootNodes)
{
for (int j = 0; j < 3; j++)
{
totalNodes++;
Console.Write(string.Format(" {0}({1}) ", totalNodes, rootNode.Key));
Node childNode = new Node() {Key = totalNodes, Nodes = new List<Node>(), ParentNode = t.RootNode};
rootNode.Nodes.Add(childNode);
newRootNodes.Add(childNode);
}
Console.Write(" ");
}
Console.WriteLine();
rootNodes = newRootNodes;
}
return t;
}
This method is supposed to print a tree, but node is null in some case:
static void PrintTreeParallel(Node rootNode)
{
List<Node> rootNodes = new List<Node>();
List<Node> newRootNodes = new List<Node>();
rootNodes.Add(rootNode);
Console.WriteLine(rootNode.Key);
while (rootNodes.Count > 0)
{
newRootNodes = new List<Node>();
Parallel.ForEach(rootNodes, node =>
{
if (node != null)
{
Console.Write(string.Format(" {0} ", node.Key));
if (node.Nodes != null)
Parallel.ForEach(node.Nodes,
newRoot => { newRootNodes.Add(newRoot); });
}
else
{
//HOW CAN WE GET HERE?????
Debugger.Break();
Console.WriteLine(rootNodes.Count);
}
});
Console.WriteLine();
rootNodes = newRootNodes;
}
}
Execute:
static void Main(string[] args)
{
var t = GenerateTree();
Console.WriteLine("Tree generated");
PrintTreeParallel(t.RootNode);
Console.WriteLine("Tree printed paral");
Console.ReadLine();
}
Question:
What's wrong here?
Why node is null in some case?
And it happens only when there are a lot of generated nodes. For ex if there would be only 10 nodes everything is OK.
The problem is that you have this code:
Parallel.ForEach(node.Nodes, newRoot => { newRootNodes.Add(newRoot); });
Which allows multiple threads to add items to the newRootNodes list concurrently. As a commenter pointed out, List<T> is not thread-safe. What's probably happening is that one thread's Add is being interrupted by another thread's call to Add, which causes an internal index in the list to be incremented. That leaves a null value in one of the list's items.
Then, later in the loop you have:
rootNodes = newRootNodes;
Which puts the corrupted list as the list that's going to be iterated by the while.
You have a data race here:
Parallel.ForEach(node.Nodes,
newRoot => { newRootNodes.Add(newRoot); });
Adding to a list with multiple threads is not thread-safe and will cause undetermined behavior.
First try to run this part with a simple foreach and see if the problem goes away. Running two nested Parallel.ForEach statements is definitely a bizarre choice.
List<T> is indeed not thread safe, so rootNode.Nodes.Add(childNode); is dropping data in unpredictable ways.
Instead of using List<> use ConcurrentBag<> and it will all work. Note that ConcurrentBag<T> is unordered, but that is fine because you have no way of predicting the order from the threads anyway.