How to evaluate expression tree with logical operators in C# - c#

I have a tree structure with leaf nodes containing expressions, which are asserted to be True or False , connected by Logical (AND/OR) conditions. I am looking for an algorithm/solution to evaluate the tree by Depth-first-search, based on logical-operators
If the parent node is an AND then no further traversal to sibling is required if the current node is evaluated as false. (also if the current node is TRUE then no further sibling to be visited if the parent node is an OR) - This would optimize the evaluation.I am just curious to know if there is a solution/code already there, rather than reinventing it.
public class TreeNode<T>
{
private readonly T _value;
private readonly List<TreeNode<T>> _children = new List<TreeNode<T>>();
public TreeNode(T value)
{
_value = value;
}
public TreeNode<T> this[int i]
{
get { return _children[i]; }
}
public TreeNode<T> Parent { get; private set; }
public T Value { get { return _value; } }
public ReadOnlyCollection<TreeNode<T>> Children
{
get { return _children.AsReadOnly(); }
}
public TreeNode<T> AddChild(T value)
{
var node = new TreeNode<T>(value) {Parent = this};
_children.Add(node);
return node;
}
public TreeNode<T>[] AddChildren(params T[] values)
{
return values.Select(AddChild).ToArray();
}
public bool RemoveChild(TreeNode<T> node)
{
return _children.Remove(node);
}
public void Traverse(Action<T> action)
{
action(Value);
foreach (var child in _children)
child.Traverse(action);
}
public IEnumerable<T> Flatten()
{
return new[] {Value}.Union(_children.SelectMany(x => x.Flatten()));
}
}
Note: I could easily do a recursive BFS in C#, But found this one tougher
Image of sample tree structure

Do a recursive traversal of the tree. You collect the result of evaluating each child node, then apply your logical operation and return the result. The basic logic would be like below.
The code is a C#-like pseudocode. It's not clear to me from the code you posted how you differentiate between operator nodes (AND and OR) from nodes that have values True and False. But you should be able to use this basic algorithm with a few changes to fit your code.
bool EvaluateNode(TreeNode node)
{
// if it's a child node, return its value
if (node has no children)
{
return node._value;
}
switch node.Operator
{
case operator.AND:
// for AND, we can shortcut the evaluation if any child
// returns false.
for each child
{
if (EvaluateNode(child) == false)
return false;
}
// all children returned true, so it's true
return true;
case operator.OR:
// for OR, we can shortcut the evaluation if any child
// returns true.
for each child
{
if (EvaluateNode(child) == true)
return true;
}
// none were true, so must be false
return false;
default:
// Unknown operator. Some error.
break;
}
}
If you don't want to do shortcut evaluation, this still works. You just change your loops slightly. For example, the AND case would be:
bool result = true;
for each child
{
result = result & EvaluateNode(child);
}
return result;
And the OR case would be:
bool result = false;
for each child
{
result = result | EvaluateNode(child);
}
return result;

Related

How to iterate all child properties recursively while setting values

I have a tree view class.
public class TreeNode
{
public int Id {get;set;}
public HashSet<TreeNode> ChildNodes {get;set;}
public TreeNode ParentNode {get;set;}
public bool IsExpanded {get;set;}
}
All tree items have IsExpanded = false by default.
When I get the leaf node, I need to expand the node and all its parent nodes, all the way up to the root node.
This is what I have tried so far:
//
// This method will return all Ids for the node and all its parent nodes.
//
private IEnumerable<int> YieldIdsRecursively(TreeNode node)
{
yield return node.Id;
if (node.ParentNode is not null)
{
foreach (int id in YieldIdsRecursively(node.ParentNode))
{
yield return id;
}
}
}
//
// I wanted to use the ref modifier to set the Id property of each node.
// However, properties are not supported by the ref modifier in c#
//
private void ExpandNodesRecursively(IEnumerable<int> ids, ref HashSet<TreeNode> nodes)
{
foreach(var node in nodes)
{
if(ids.Contains(node))
{
node.IsExpanded = true;
}
if((node.ChildNodes?.Count ?? 0) > 0)
{
//
// This is where the error pops
//
ExpandNodesRecursively(ids, node.ChildNodes);
}
}
}
Any advises would be greatly appreciated!
Well, I think it's easier to return TreeNode itself instead of its Id:
private IEnumerable<TreeNode> ThisAndAllParents() {
for (TreeNode current = this; current != null; current = current.ParentNode)
yield return current;
}
then ExpandNodesRecursively can be something like this:
private void ExpandNodesRecursively() {
foreach (TreeNode node in ThisAndAllParents())
node.IsExpanded = true;
}

Return the list of items which are part of the longest path from Tree's root to a Leaf in a General Tree [duplicate]

This question already has answers here:
Find the maximum depth of a tree
(5 answers)
Closed 2 years ago.
Given this Class that represents a tree , i got a little confused on how would i return a list that will consist of nodes that are part of the tree's height .
public class TreeNode<T>
{
private T m_Data;
public T Data
{
get
{
return m_Data;
}
set
{
m_Data = value;
}
}
private readonly List<TreeNode<T>> m_Children;
public List<TreeNode<T>> Children
{
get
{
return m_Children;
}
}
public TreeNode(T i_Data)
{
this.m_Data = i_Data;
m_Children = new List<TreeNode<T>>();
}
public void AddChild(T data)
{
m_Children.Add(new TreeNode<T>(data));
// return m_Children[m_Children.Count-1];
}
public List<T> LongestPathNodes(TreeNode<T> i_node)//this function
{
if(i_node.m_Children.Count == 0)
{
List<T> choosenMove = new List<T>(1);
choosenMove.Add(i_node.Data);
return choosenMove;
}
else
{
foreach(TreeNode<T> treeNode in i_node.Children)
{
}
}
}
The function which i'm talking about is the "LongestPathNodes" Function ,I think it has to be recursive , i wrote part of it but i'm confused on how should i proceed , given the fact that the tree does not have to be a binary one .
Define a Height property:
public int Height =>
m_Children != null && m_Children.Any()
? m_Children.Max(x => x.Height) + 1
: 1;
Now you can return the nodes of the longest branch from any given node:
public IEnumerable<TreeNode<T>> LongestPathNodes()
{
yield return this;
var children = m_Children?
.OrderByDescending(x => x.Height)
.FirstOrDefault()?
.LongestPathNodes();
if (children != null)
{
foreach (var child in children) yield return child;
}
}
If you need this as a List<T> it is a LINQ one-liner:
var list = node.LongestPathNodes().Select(x => x.m__Data).ToList();

Search tree, simplest method for traversing c#

I need to be able to search a tree with arbitrary many children.
It could look like this.
P
/ | \
C C C layer 1
/ | \
C C C layer 2
|
C layer 3
/ | \
C C C layer 4
With arbitrary many children in each C.
Is it convinient to have a double linked list for each start node in layer 1? (In layer 1 the non expanding nodes might also ofcourse expand).
I need to evaluate and work with every sub-tree.
Whats the simplest method?
Or maybe some kind of depth first search/breadth first search is better?
The tree is constructed on the fly.
thanks
The easiest way to do this is using recursion.
Let's assume that your tree stores items of type T, and that type implements IEquatable<T>.
Firstly, let's write a very basic tree class:
public sealed class Node<T>
{
public Node(T value) { Value = value; }
public T Value { get; }
public IEnumerable<Node<T>> Children => _children;
public void Add(Node<T> child)
{
_children.Add(child);
}
readonly List<Node<T>> _children = new List<Node<T>>();
}
Now we can write a method to search that tree using recursion very simply.
This will return the first node containing the specified value if it was found, or null if no such node was found.
public static Node<T> Find<T>(Node<T> root, T target) where T: IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
return root;
foreach (var child in root.Children)
{
var found = Find(child, target);
if (found != null)
return found;
}
return null;
}
It's easy to adapt this to return ALL nodes that match the target:
public static IEnumerable<Node<T>> FindAll<T>(Node<T> root, T target) where T : IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
yield return root;
foreach (var child in root.Children)
{
var found = FindAll(child, target);
foreach (var item in found)
yield return item;
}
}
For demo purposes, here's a compilable console application. It includes a makeTree() method which I'm using to make a tree of depth 4 where each node has 5 children.
Then it uses Find<T>(Node<T> root, T target) to recursively search the tree to find the specified target values. One will succeed, the other will fail:
using System;
using System.Collections.Generic;
namespace Demo
{
public sealed class Node<T>
{
public Node(T value) { Value = value; }
public T Value { get; }
public IEnumerable<Node<T>> Children => _children;
public void Add(Node<T> child)
{
_children.Add(child);
}
readonly List<Node<T>> _children = new List<Node<T>>();
}
class Program
{
static void Main()
{
var root = makeTree(1, 1, 4, 5);
lookFor(root, "3.4");
lookFor(root, "6.3");
}
static void lookFor<T>(Node<T> root, T target) where T: IEquatable<T>
{
var found = Find(root, target);
Console.WriteLine(found != null ? $"Found {target}" : $"Did not find {target}");
}
public static Node<T> Find<T>(Node<T> root, T target) where T: IEquatable<T>
{
if (root.Value != null && root.Value.Equals(target))
return root;
foreach (var child in root.Children)
{
var found = Find(child, target);
if (found != null)
return found;
}
return null;
}
static Node<string> makeTree(int id1, int id2, int depth, int nChildren)
{
var root = new Node<string>($"{id1}.{id2}");
if (depth == 0)
return root;
for (int i = 0; i < nChildren; ++i)
root.Add(makeTree(id1+1, i+1, depth-1, nChildren));
return root;
}
}
}

how to find a NodeData in tree of Nodes?

I have a Node structure as below,this Node has stringdata and list of nodes as it's children. I wanted to search a data in this tree
I wrote a recursive function FindNode(Node intree,string target)
public class Node
{
public string Data;
public List<Node> Children = new List<Node>();
//some code
public Node(string r)
{
this.Data = r;
}
public string getData()
{
return this.Data;
}
//some code
public List<Node> getchildren()
{
return this.Children;
}
//some code
}
target is the string which I want to find and the intree is the begining of the tree(ROOT)
I have problem after while loop what should I return after that?
If I am wrong how should I write it?
public Node FindNode(Node intree,string target)
{
if(intree.getData()==target)
return intree;
else
{
while(intree.getchildren()!=null)
{
foreach(Node n in intree.getchildren())
{
FindNode(n,target);
}
}
}
}
Use this one:
public Node FindNode(Node intree,string target)
{
if(intree.getData()==target)
return intree;
else
{
foreach(Node n in intree.getchildren())
{
Node node = FindNode(n,target) ; //CHECK FOR RETURN
if(node != null)
return node;
}
}
return null;
}
The difference is that I checked for return of FindNode method, and if it's not null, return result.
Just note that in case of dupplicated nodes in the tree (nodes with the same string) it will return first occuarance.
Given that there could be more than one match in the tree you would be better off returning an IEnumerable<Node>. Also you don't need to put those odd get methods in there. And finally did you mean to only search leaf nodes or did you want to search all nodes (the else statement)?
public IEnumerable<Node> FindNode(Node intree,string target)
{
if(intree.Data ==target)
yield return intree;
foreach (var node in intree.Children.SelectMany(c => FindNode(c, target))
yield return node;
}
If you want the first matching node, just call First() on the result. If you want to make sure there is only one, call Single() on it.
I would recommend you to return null and apply check where you are calling this method that if null is returned then it means no node found. Code is as follow
public static Node FindNode(Node intree, string target)
{
if (intree.getData() == target)
return intree;
foreach (Node node in intree.getchildren())
{
Node toReturn = FindNode(node, target);
if (toReturn != null) return toReturn;
}
return null;
}
public Node FindNodeRecursively(Node parentNode, string keyword)
{
if(parentNode.getData() == keyword)
{
return parentNode;
}
else
{
if(parentNode.Children != null)
{
foreach(var node in parentNode.Children)
{
var temp = FindNodeRecursively(node, keyword);
if(temp != null)
return temp;
}
}
return null;
}
}

Stop the recursion completely when returning something

I do recursion to find a long value within a List with multiple children that also can have children.
following method:
public TaxonomyData getTaxonomyData(long taxId, List<TaxonomyData> TaxonomyTree, TaxonomyData output)
{
//find taxid in the taxonomy tree list and return the taxonomydata
foreach (TaxonomyData td in TaxonomyTree)
{
if (td.TaxonomyId == taxId)
{
output = td;
//return td; => when doing a return here means I already found a match so it is not necessary to do all the recursion.
}
else if (td.Taxonomy.Length > 0)
{
getTaxonomyData(taxId, td.Taxonomy.ToList(), output);
}
}
return output;
}
Is it possible when I do return td; (see commented row) that my whole recursion stops?
Thanks
I suspect you want something like:
public TaxonomyData GetTaxonomyData(long taxId, IEnumerable<TaxonomyData> tree)
{
foreach (TaxonomyData td in tree)
{
if (td.TaxonomyId == taxId)
{
return td;
}
else
{
// See if it's in the subtree of td
TaxonomyData data = GetTaxonomyData(taxId, td.Taxonomy);
if (data != null)
{
return data;
}
}
}
// Haven't found it anywhere in this tree
return null;
}
Each return only returns one level, but by checking the return value in the else clause, we can return all the way up the stack when we find the right value.
The final result returned to the caller will be a null reference if it hasn't been found.
Note that I've removed the "output" parameter, which wouldn't have been effective anyway as it wasn't a ref parameter, and isn't as clear as just using the return value.
A linq extension solution i came up with, probably slower but there you go..
public static class Ext
{
public static T SingleOrDefault<T>(this IEnumerable<T> enumerable,Func<T,bool> predicate, Func<T,T> defaultSelector)
where T : class
{
return enumerable.SingleOrDefault(predicate) ?? enumerable.SkipWhile<T>(t=>defaultSelector(t) == null).Select(defaultSelector).SingleOrDefault();
}
public static TaxonomyData Get(this IEnumerable<TaxonomyData> tree, int taxId)
{
return tree.SingleOrDefault(t=> t.TaxonomyId == taxId,t=>t.Taxonomy.Get(taxId));
}
}

Categories