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;
}
}
}
Related
I am given this set of code and I need to fill it up with some code above the while loop and in the While loop. I have seen some documentation but all i have seen is search methods with two arguments and this one only has one. I already wrote the part inside the while loop but im note sure if that is correct. How can I finish this code so that it searches for the value given as the parameter?
note: this is not a homework assignment where I ask you to do it for me, rather this is one of the few resources we have for studying and if you could complete this it would give me a better grasp.
When I run this code now I get this error message:
Type "Tests.Node" does not contain a definition for "value" and no extension method "value" of type "Tests.Node" could be found. Are you missing an assembly reference?
{
public class Node<T> where T : IComparable
{
public T Value { get; }
public Node<T> Next { get; set; }
public Node(T value, Node<T> next)
{
this.Value = value;
this.Next = next;
}
}
public class LinkedList<T> where T : IComparable
{
public Node<T> start;
public LinkedList()
{
start = null;
}
public LinkedList(Node<T> node)
{
start = node;
}
public Node<T> Search(T value)
{
[here is code needed]
while (start != null)
if(start.value.CompareTo(value) == 0){
return start;
}
start = start.next;
}
}
public class Program {
public static void Main(string[] args){
var list =
new LinkedList<int>(
new Node<int>(
5, new Node<int>(
7, new Node<int>(
21, new Node<int>(
30, null)
)
)
)
);
var a = 21;
var fr = list.Search(a);
}
}
}
You are very close to correct solution. First of all you need to fix compiler errors - change value and next to Value and Next, cause that how properties on your Node class are called.
Next you need to add curly brackets so the while block will execute assignment start = start.Next; (currently only if statement is inside while, so you will end with infinite loop)
Next you need to fix return - add return null; after while block - value you will return if nothing is found (also without it code will not compile).
Lastly you will need to fix the issue with changing the list during search (you are modifying start field of your LinkedList class with start = start.Next, you should not do that), introduce a temporary variable (i've name it curr), assign it value of start and use it in your while loop:
public Node<T> Search(T value)
{
var curr = start;
while (curr != null)
{
if (curr.Value.CompareTo(value) == 0)
{
return curr;
}
curr = curr.Next;
}
return null;
}
I suggest implementing IEnumerable<Node<T>> interface
public class Node<T> : IEnumerable<Node<T>> where T : IComparable {
public IEnumerator<Node<T>> GetEnumerator() {
for (Node<T> item = this; item != null; item = item.Next)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
...
Then you can use Linq to query the collection:
using System.Linq;
...
public static void Main(string[] args) {
LinkedList<int> list = ...
int a = 21;
var fr = list.start.FirstOrDefault(item => item.Value == a);
I have a class as follows:
public class SiloNode
{
public string Key { get; private set; }
public string ParentKey { get; private set; }
public string Text { get; private set; }
public string Url { get; private set; }
}
All nodes are contained in a list:
List<SiloNode> nodes = new List<SiloNode>();
As you can see, the class contains a ParentKey property, so it's possible to find the item's parent, grandparent etc, until the top of the list is hit.
At present, I need to traverse up 2 levels, and you can see from the code below, it's already looking quite clunky. Now I need to modify the code to traverse up 3 levels and I'm concerned it's getting messy.
Is there a cleaner way to achieve what I want?
string GetStartGroup(string currentUrl)
{
string startGroup = null;
var currentNode = Silos.Silo.SingleOrDefault(x => x.Url == currentUrl);
if (currentNode != null)
{
var parentNode = Silos.Silo.SingleOrDefault(x => x.Key == currentNode.ParentKey);
if (parentNode != null) startGroup = parentNode.ParentKey;
}
return startGroup;
}
Repeatedly using SingleOrDefault on a list makes the algorithm rather slow: finding parents for n nodes requires an O(n2) time.
You should make a Dictionary<string,SiloNode> first, and then traverse up the hierarchy through the dictionary:
var lookup= nodes.ToDictionary(n => n.Key);
...
SiloNode FindParent(SiloNode node, int levelsUp, IDictionary<string,SiloNode> lookup) {
while (node != null && levelsUp != 0) {
if (node.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
levelsUp--;
}
return node;
}
This will look up a parent up to levelsUp levels up. If you are looking for the last possible parent, modify the code as follows:
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
while (true) {
if (node?.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
}
}
or recursively
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
return node?.ParentKey != null && lookup.TryGetValue(node.ParentKey, out var parent)
? FindParent(parent, lookup)
: node;
}
You can do this with recursion.
string GetStartGroup(string currentUrl)
{
var node = nodes.Single(x => x.Url == currentUrl);
if (node.ParentKey == null)
return node.Key;
return GetStartGroup(nodes.Single(x => x.Key == node.ParentKey).Url);
}
Alternatively:
string GetStartGroup(string currentUrl)
{
return GetStartNode(nodes.Single(x => x.Url == currentUrl)).Key;
}
SiloNode GetStartNode(SiloNode node)
{
if (node.ParentKey == null)
return node;
return GetStartNode(nodes.Single(x => x.Key == node.ParentKey));
}
You can change
if (parentNode != null) startGroup = parentNode.ParentKey;
to
if (parentNode != null) startGroup = GetStartGroup(currentNode.parentUrl /*or something similar*/);
However, it would be better to use an iterative loop. I do not know about your problem enough to give you a hint, but the pseudocode would look like this:
while (parentNode != null) {
currentNode = currentNode.parentNode;
parentNode = currentNode.parentNode;
}
You might need to call SingleOrDefault, but if you have a direct reference, you should use that instead.
just put it into a method:
public static Silo Up(Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
or as Extension method:
public static SiloExtensions
{
public static Silo Up(this Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
}
so you can just do silo.Up()?.Up()
Please note that this is rather slow.
Depending on what you actually do, you may want to introduce actual Parent-Object as a field or a wrapper object providing access to it.
Such a wrapper object might look like this:
public class SiloWrapper
{
public Silo Wrapped { get; }
public Silo Parent { get; }
private SiloWrapper(Silo silo, Silo parent)
{
this.Wrapped = silo;
this.Parent = parent;
}
public IEnumerable<SiloWrapper> Map(IEnumerable<Silo> silos)
{
var dict = silos.ToDictionary((s) => s.Key);
foreach(var s in silos)
{
yield return new SiloWrapped(s, s.ParentKey == null ? null : dict[s.ParentKey]);
}
}
}
to then traverse up and down, you just would need to call SiloWrapped.Map(<methodToGetSiloCollection>) and have all wrapped silos ready for usage.
If GarbageCollection may be a concern, you also can use WeakReference<Silo> ParentWeak instead
For a school project I am making an RPN calculator. This calculator has an abstract class Stack where three different implementations of stacks derive from. One of them is a linked list stack. For these stacks I have to show what values are on the stack. To do this I use an array. For my arraystack and list stack it was easy, but I can't figure out how to convert a linked list to an array. What is the best way to do that?
This is the code that I use for my linked list.
public class Node
{
public int data;
public Node next;
public Node(int i)
{
data = i;
next = null;
}
public void Add(int i)
{
if (next == null)
{
next = new Node(i);
}
else
{
next.Add(i);
}
}
}
public class MyLinkedList
{
private Node headNode;
private int count;
public MyLinkedList()
{
headNode = null;
count = 0;
}
public int Count()
{
return count;
}
public void Add(int i)
{
if (headNode == null)
{
headNode = new Node(i);
}
else
{
headNode.Add(i);
}
count++;
}
Implement IEnumerable on your LinkedList
using System.Linq;
Call ToArray on the LinkedList.
Implementing IEnumerable is trivial. Simply start at the root node in your list, yield return Node.data;, and move to the next node. Rinse and repeat until the next node is null.
Add a new method to your class.
public class MyLinkedList
{
... keep existing methods here ...
public int[] ToArray() {
var result = new int[count]();
var index = 0;
var node = headnode;
while (node != null) {
result[index] = node.data;
node = node.next;
}
return result;
}
Eh... Something like that?
public class MyLinkedList {
...
public Node[] ToArray() {
// You´ve got pre-computed count - let´s use it
Node[] result = new Node[count];
Node node = headNode;
for (int i = 0; i < result.Length; ++i) {
result[i] = node;
node = node.next;
}
return result;
}
}
P.S. public fields like next in the Node class is a bad practice. Convert them into properties
As #Will suggested, I would implement IEnumerable<int> by your class. That will bring you to powerful world of LINQ where you will be able to convert your linked list to array, list, or just filter nodes:
public class MyLinkedList : IEnumerable<int>
{
// your code here
public IEnumerator<int> GetEnumerator()
{
Node current = headNode;
while(current != null)
{
yield return current.data;
current = current.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now you can use all LINQ extensions with your class:
MyLinkedList myList = new MyLinkedList();
myList.Add(10);
myList.Add(15);
myList.Add(20);
int[] array = myList.ToArray();
List<int> list = myList.ToList();
// items above 13
var items = myList.Where(i => i > 13);
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;
}
}
i use the solution in this link not work
Deep cloning objects
the following code, can not copy to a new tree, mutate will affect the original tree root(root)
foreach (Bag b in bag_list)
{
if (b.cards.Count() == 2)
{
Node original_root = new Node();
original_root = (Node)root.Clone(); // copy to a new tree
target_list = choose_valid_target(target_list, b.cards, b.cards.Count() - 1);
foreach (Target t in target_list)
{
Console.WriteLine("op:" + t.op + ", label:" + t.label);
Node mutated_root = mutate(original_root, target_list);
result = "";
result = inorder(mutated_root, result); // get inorder
Console.WriteLine(result.Substring(1, result.Length - 2)); //print
}
}
}
public class Node : System.Object, ICloneable
{
public int priority;
/*
7 alphabet
6 (,)
5 *,/,%
4 +,-
3 <,<=,>,>=
2 &&,||
1 =
*/
public string Data;
public Node Left;
public Node Right;
public string Label;
public object Clone()
{
//return this as object;
return this.MemberwiseClone();
//return new Node() as object;
}
}
public Node mutate(Node root, List<Target> targets) // mutate
{
if (root != null)
{
if (!IsLeaf(root.Left.Data))
mutate(root.Left, targets);
foreach (Target target in targets)
{
if (root.Label == target.label)
{
root.Data = target.op;
}
}
if (!IsLeaf(root.Right.Data))
mutate(root.Right, targets);
}
return root;
}
Clone all nodes recursively:
public object Clone()
{
Node clone = (Node)MemberwiseClone();
if (Left != null)
clone.Left = (Node)Left.Clone();
if (Right != null)
clone.Right = (Node)Right.Clone();
return clone;
}