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;
}
}
Related
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;
}
I have a very simple implemention of BST in C#. The code:
class Node
{
public int? value;
public Node parent;
public Node left;
public Node right;
public Node(int? value, Node parent = null)
{
this.value = value;
this.parent = parent;
}
}
class BST
{
public Node root;
public List<Node> tree = new List<Node>();
public BST(int? value = null)
{
if (value != null)
{
this.root = new Node(value);
this.tree.Add(this.root);
}
}
public Node insert(int value)
{
Node node = this.root;
if (node == null)
{
this.root = new Node(value);
this.tree.Add(this.root);
return this.root;
}
while (true)
{
if (value > node.value)
{
if (node.right != null)
{
node = node.right;
}
else
{
node.right = new Node(value, node);
node = node.right;
break;
}
}
else if (value < node.value)
{
if (node.left != null)
{
node = node.left;
}
else
{
node.left = new Node(value, node);
node = node.left;
break;
}
}
else
{
break;
}
}
return node;
}
}
class Program
{
static void Main()
{
BST superTree = new BST(15);
superTree.insert(14);
superTree.insert(25);
superTree.insert(2);
}
}
My Question is regarding the "Insert" method of the BST class.
How exactly its "return" work when I just call it in the main method?
How does it know to put that "node" on the "left"? I am not referencing "root.left" anywhere but somehow it gets properly inserted.
I realized at some point that some kind of recursion occurs there, but its been like 6 hours and I still can't understand how this method properly works.
I appreaciate any explanation of that "insert" method.Thanks.
Node node = this.root;
Your code always starts with the root, because of this line. It's only after node is no longer null that node be re-assigned to something other than root. The rest of the code works on node.left, but because your code begins with root as above, node.left is actually referencing root at the start.
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;
I've tried to implement a binary-search-tree(BST) insert using the following method but i really don't get why i get the value instead of the actual "reference" to the node.
I've done other implementations that worked fine but I really want to understand why instead of getting the pointer to let's say node.m_left I get just it's value (null).
How can I get that without resorting to unsafe code ?
The reason i'm choosing this way is because searching and inserting are closely related and i don't want to implement the same thing twice.
public void Add(int value)
{
if (root == null)
{
root = new Node(value);
return;
}
Node parent = null ,
res;
//finding the correct place
res = Find(value, root, ref parent);
if (res == null) //probably redunant
{
//once found create a node and asign it's parent
res = new Node(value);
res.m_parent = parent;
}
//EvaluateAVT(res);
}
private Node Find(int value, Node node, ref Node parent,bool justfind = false)
{
if (node.Data == value && justfind)
{
return node;
}
if (node.Data >= value)
{
if (node.m_left == null)
{
parent = node;
return node.m_left;
}
return Find(value,node.m_left,ref parent ,justfind);
}
else
{
if (node.m_right == null)
{
parent = node;
return node.m_right;
}
return Find(value, node.m_right, ref parent, justfind);
}
}
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));
}
}