Traversing a Tree Structure - c#

I am trying to understand how to traverse a tree data structure, and I am having a problem doing it, especially as I am trying to use IEnumerable. I want the tree as a dictionary so I can refer to the nodes by their string names. The tree will hold different class objects but as these objects all implement an interface IMyInterface, type of the tree will be the IMyInterface interface.
I have the tree:
internal class Tree<T>
{
private TreeNode<T> root;
internal Tree(T value)
{
if (value == null)
{
throw new ArgumentNullException(
"Cannot use a null value to construct a tree.");
}
this.root = new TreeNode<T>(value);
}
internal Tree(T value, params Tree<T>[] children) : this(value)
{
foreach (Tree<T> child in children)
{
this.root.AddChild(child.root);
}
}
internal TreeNode<T> Root
{
get { return this.root; }
}
private void PrintDFS(TreeNode<T> root, int spaces)
{
if (spaces < 0)
{
throw new ArgumentOutOfRangeException(
"The number of spaces used to represent the parent-child relation in a tree must be greater than or equal to zero.");
}
if (this.root == null)
{
return;
}
StringBuilder sb = new StringBuilder();
sb.Append(' ', spaces);
sb.Append(root.Value);
TreeNode<T> child = null;
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
}
// Traverses and prints the tree in
// Depth-First Search (DFS) manner
internal void TraverseDFS()
{
this.PrintDFS(this.root, 0);
}
}
And my node class is:
internal class TreeNode<T> : IEnumerable<TreeNode<T>>
{
private T value;
private bool hasParent;
private readonly Dictionary<string, TreeNode<T>> children = new Dictionary<string, TreeNode<T>>();
internal TreeNode(T value)
{
if (value == null)
{
throw new ArgumentNullException(
"Cannot insert null values for a tree node!");
}
this.value = value;
this.children = new Dictionary<string, TreeNode<T>>(); // dictionary that holds the children of each node
}
internal T Value
{
get { return this.value; }
set { this.value = value; }
}
internal int ChildrenCount
{
get
{
return this.children.Count;
}
}
internal void AddChild(TreeNode<T> child)
{
if (child == null)
{
throw new ArgumentNullException(
"Cannot insert null value as child node.");
}
if (child.hasParent)
{
throw new ArgumentException(
"The child node already has a parent.");
}
child.hasParent = true;
this.children.Add(child.ToString(), child);
}
internal TreeNode<T> GetChild(string nodeName)
{
return this.children[nodeName];
}
internal IEnumerator<TreeNode<T>> GetEnumerator()
{
return this.children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator<TreeNode<T>> IEnumerable<TreeNode<T>>.GetEnumerator()
{
throw new NotImplementedException();
}
}
The issue seems to be the code:
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
(Code snippet from the Tree class) Any suggestions would be greatly appreciated.
EDIT
I get the error messages:
Error 669 A local variable named 'child' cannot be declared in this scope because it would give a different meaning to 'child', which is already used in a 'parent or current' scope to denote something else.
Error 672 Cannot convert type TreeNode<T> to Tree<T>
And the warning message:
Warning 668 TreeNode<T> does not implement the 'collection' pattern. TreeNode<T>.GetEnumerator() is either static or not public.

Issue #1
Error 669 A local variable named 'child' cannot be declared in this
scope because it would give a different meaning to 'child', which is
already used in a 'parent or current' scope to denote something else.
TreeNode<T> child = null;
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
You already have a child variable. You need to name them differently. The error is pretty self explanatory.
For this situation, just remove child from above the foreach since it is useless there.
foreach (var child in this.root)
{
PrintDFS(child, spaces);
}
I think you wanted TreeNode<T>, but not sure what was supposed to actually return out of root.
Issue #2
Error 672 Cannot convert type TreeNode to Tree
If you're supposed to be looping over TreeNode<T>, not Tree<T> as the error states. Just use var unless you are actually trying to iterates trees and not nodes.
Issue #3
Warning 668 TreeNode does not implement the 'collection' pattern. TreeNode.GetEnumerator() is either static or not public.
It needs to be public. Internal does not cut it because it needs to adhere to the IEnumerable contract. Looks like you have that solved though with the explicit implementation of it.

First, replace your 3 GetEnumertor functions with these 2:
public IEnumerator<TreeNode<T>> GetEnumerator()
{
return this.children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
Then change the last part of your PrintDFS loop as follows:
//TreeNode<T> child = null;
foreach (var child in this.root)
{
PrintDFS(child, spaces);
}
That compiles.

Related

Mapping binary search tree

I have this binary search tree with Node class and I need to write mapping and filtering method for it but I have no clue how can I go through the whole tree. My every attempt to go through it skipped almost half of the tree.
public class BST<T> where T:IComparable<T>
{
public class Node
{
public T value { get; }
public Node left;
public Node right;
public Node(T element)
{
this.value = element;
left = null;
right = null;
}
}
private Node root;
private void add(T element)
{
if (root == null)
root = new Node(element);
else
{
add(element, root);
}
}
public void add(T element, Node leaf)
{
if(element.CompareTo(leaf.value) > 0)
{
if (leaf.right == null)
leaf.right = new Node(element);
else
add(element,leaf.right);
}
else
{
if (leaf.left == null)
leaf.left = new Node(element);
else
add(element, leaf.left);
}
}
}
I have no clue how can I go through the whole tree
There are many ways to do that. One is to make your class iterable.
For that you can define the following method on your Node class:
public IEnumerator<T> GetEnumerator()
{
if (left != null) {
foreach (var node in left) {
yield return node;
}
}
yield return value;
if (right != null) {
foreach (var node in right) {
yield return node;
}
}
}
And delegate to it from a similar method on your BST class:
public IEnumerator<T> GetEnumerator()
{
if (root != null) {
foreach (var node in root) {
yield return node;
}
}
}
Now you can write code like this:
var tree = new BST<int>();
tree.add(4);
tree.add(2);
tree.add(3);
tree.add(6);
tree.add(5);
foreach (var value in tree) {
Console.WriteLine(value);
}
I need to write mapping and filtering method for it
It depends on what you want the result of a mapping/filtering function to be. If it is just a sequence of values, the above should be simple to adapt. If a new tree should be created with the mapped/filtered values, then feed these values back into a new tree (calling its add), or (in case of mapping) use the same recursive pattern of the above methods to create a new method that does not do yield, but creates a new tree while iterating the existing nodes, so the new tree has the same shape, but with mapped values.

Binary search tree implementation. Seems to fail at adding new values and searching for existing ones

Generic implementation in C#. A very quick example, so obviously the code can be improved quite a bit, however at the moment I want to get it to work in its current form.
Adding new nodes, or deleting existing ones, does not work. When the print() method is called in the driver program:
BinarySearchTree<int> testTree = new BinarySearchTree<int>(1);
Console.WriteLine("Binary search tree contains 0: " + testTree.exists(0));
Console.WriteLine("Binary search tree contains 1: " + testTree.exists(1));
Console.WriteLine("Binary search tree contains 2: " + testTree.exists(2));
testTree.add(2);
Console.WriteLine("Binary search tree contains 2: " + testTree.exists(2));
testTree.remove(1);
Console.WriteLine("Binary search tree contains 1: " + testTree.exists(1));
testTree.print();
Console output for the above:
Binary search tree contains 0: False
Binary search tree contains 1: True
Binary search tree contains 2: False
Binary search tree contains 2: False
Binary search tree contains 1: True
1
Checked with setting breakpoints at the appropriate methods, no closer to finding the problem.
Code for this class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace BinaryTree
{
public class BinarySearchTree<T> where T : IComparable
{
#region private members
private class Node
{
public T value;
public Node left;
public Node right;
}
private Node rootNode;
private void insert(Node root, Node node)
{
if (root==null)
{
root = node;
}
else if (isLessThan(node.value,root.value))
{
insert(node.left, node);
}
else if (isGreaterThan(node.value,root.value) || (isEqual(root.value,node.value)))
{
insert(node.right, node);
}
}
private void displayInOrder(Node node)
{
if (node != null)
{
displayInOrder(node.left);
Console.WriteLine(node.value);
displayInOrder(node.right);
}
}
#region comparison helper functions
private bool isGreaterThan(T a, T b)
{
return a.CompareTo(b) > 0;
}
private bool isLessThan(T a, T b)
{
return a.CompareTo(b) < 0;
}
private bool isEqual(T a, T b)
{
return a.CompareTo(b) == 0;
}
#endregion
#endregion
// ctor
public BinarySearchTree(T rootValue)
{
rootNode = new Node();
rootNode.value = rootValue;
rootNode.left = null;
rootNode.right = null;
}
public void add(T value)
{
// first create a new node. Eventually, it will be added to the tree.
Node newNode = new Node();
newNode.value = value;
newNode.left = null;
newNode.right = null;
// give this node to the insert method, which will traverse the tree until it finds the correct place to insert it.
insert(rootNode, newNode);
}
public bool exists(T value)
{
Node node = rootNode;
while (node!=null)
{
if (isEqual(node.value,value))
{
return true;
}
else if (isLessThan(value,node.value))
{
node = node.left;
}
else if (isGreaterThan(value,node.value))
{
node = node.right;
}
}
return false;
}
public void remove(T value)
{
Node node = rootNode;
while (node!=null)
{
if (isEqual(node.value,value))
{
node = null;
}
else if (isLessThan(node.value, value))
{
node = node.left;
}
else if (isGreaterThan(node.value, value) || (isEqual(value, node.value)))
{
node = node.right;
}
}
}
public void print()
{
displayInOrder(rootNode);
}
}
}
Your problem is that you are assigning a value to a null, which is not a reference at all.
The null keyword is a literal that represents a null reference, one that does not refer to any object. null is the default value of reference-type variables. Ordinary value types cannot be null, except for nullable value types.
In this line of code node.right has the value null.
insert(node.right, node);
So you will assign node to a null which is no reference at all.
My suggestion would be to change the insert code like this:
Declare a direction enum
public enum Direction {
Left,
Right
}
Use the enum to update the proper reference
private void insert(Node root, Node node)
{
if (root==null)
{
root = node;
}
else if (isLessThan(node.value,root.value))
{
insert(root, node, Direction.Left);
}
else if (isGreaterThan(node.value,root.value) || (isEqual(root.value,node.value)))
{
insert(root, node, Direction.Right);
}
}
private void insert(Node root, Node node, Direction direction)
{
if (direction == Direction.Left)
{
// You are actually updating the reference left of root node
root.left = node;
}
else if (direction == Direction.Right)
{
// You are actually updating the reference right of root node
root.right = node;
}
}
The remove logic is pretty much the same. Check the comments
// I am declaring a local reference to a Node
Node node = rootNode;
while (node!=null)
{
if (isEqual(node.value,value))
{
// I am updating the local reference to null
// I am not setting the left or right value reference to null
// So that I won't be able to find it again
node = null;
}
Beware that when you detach one reference, you have to rebuild the whole tree. If you detach a link by setting null on the left, then all the left values will be detached as well.

Algorithm to Clone a Graph in C# [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 3 years ago.
Given a reference of a node in a connected undirected graph, return a deep copy (clone) of the graph. Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors.
What is the mistake in this code - Clone a graph . It says
Object Reference not set to an instance of an object in LeetCode for
this line - target.Add(C);.
Could someone share some suggestions here.
public class Node {
public int val;
public IList<Node> neighbors;
public Node(){}
public Node(int _val,IList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;}
public class Solution {
public Node CloneGraph(Node node) {
if (node == null)
{return null;}
var map = new Dictionary<int, Node>();
Queue<Node> q = new Queue<Node>();
q.Enqueue(node);
Node newNode = new Node();
newNode.val = node.val;
CopyList(node.neighbors,newNode.neighbors);
map.Add(newNode.val, newNode);
while(q.Count!=0)
{
Node head = q.Dequeue();
Node cloneU = map[head.val];
foreach (Node neighborNode in head.neighbors)
{
if(map.ContainsKey(neighborNode.val))
{
CopyList(head.neighbors,cloneU.neighbors);
}
else
{
q.Enqueue(neighborNode);
Node neighborNodeCopy = new Node(neighborNode.val,neighborNode.neighbors);
map.Add(neighborNodeCopy.val, neighborNodeCopy);
CopyList(neighborNodeCopy.neighbors,cloneU.neighbors);
}
}
}
return newNode;
}
public void CopyList(IList<Node> source, IList<Node> target)
{
foreach( Node C in source)
{
target.Add(C);
}
}
}
The specific error you're seeing is due to the fact that target is null, and you're trying to call a method (Add) on it.
To fix this, you can just set target to a new list if it's null before you try to call the .Add method on it:
public void CopyList(IList<Node> source, IList<Node> target)
{
if (target == null) target = new List<Node>();
foreach( Node C in source)
{
target.Add(C);
}
}
However, this is identical to a one-line version of the code, using the System.Linq extension method, ToList"
public void CopyList(IList<Node> source, IList<Node> target)
{
target = source?.ToList();
}
With that being said, it appears that you're trying to make a deep copy of Node, but when you do target.Add(C);, you're adding a reference to the source node instead of a clone of that node.
For deep copying, we need to make a complete copy of all reference types, and in the case of Node, the only reference type it has is the IList<Node> collection. A possibly more simple way to create a deep copy is to implement a Clone method on Node itself, which creates a new Node and then creates a new List<Node> that contains clones of each node in the list:
public class Node
{
public int Value { get; set; }
public IList<Node> Neighbors { get; set; }
public Node() { }
public Node(int val, IList<Node> neighbors)
{
Value = val;
Neighbors = neighbors;
}
public Node Clone()
{
// Start with a new node with the same value
var newNode = new Node { Value = Value };
// Deep copy the list of neighbors by returning their clones in a new list
newNode.Neighbors = Neighbors?.Select(node => node.Clone()).ToList();
// Return our deep copy
return newNode;
}
}

Mixed-Type Generic C# Stack (Linked List Implementation)

I realize that in most cases, it would be beneficial to have a homogeneous, type-safe stack, but I'm curious if this is possible, as I was asked to create a Stack for an exercise which accepts all types.
So I currently have a generic linked-list Stack class, and I'm wondering if there's any way to make the Node class generic so that the Next node can be of a different type. I know I can make the stack accept all types by just making the all the type parameters object instead of using a generic, but I was warned of the performance implications of boxing & unboxing of value types / upcasting all of it's elements to the base object class.
So I went ahead an implemented it as Generic, but was unable to find a solution that allowed different types for each Node. If I wanted to avoid the object approach, is there a possible solution? Even if it takes a different approach altogether, it doesn't necessarily have to fit this approach.
I hope this makes sense! At any rate, here's the implementation I currently have. Please let me know what you think.
Node.cs
namespace DataStructures
{
class Node<T>
{
public T Value { get; private set; }
public Node<T> Next { get; set; }
public Node(T value)
{
Value = value;
}
}
}
Stack.cs
namespace DataStructures
{
class Stack<T>
{
private Node<T> root;
public int Size { get; private set; } = 0;
public Stack()
{
}
public Stack(params T[] values)
{
foreach (var value in values)
Push(value);
}
public void Push(T value)
{
if (value == null)
throw new ArgumentNullException("value", "You cannot push a null value onto the stack");
var newNode = new Node<T>(value);
if (root != null)
newNode.Next = root;
root = newNode;
Size++;
}
public dynamic Peek()
{
if (root == null)
return null;
return root.Value;
}
public T Pop()
{
if (root == null)
throw new InvalidOperationException("The stack is empty, nothing to pop");
Size--;
var popped = root.Value;
root = root.Next;
return popped;
}
public bool TryPop(out dynamic popped)
{
if (root == null)
{
popped = null;
return false;
}
else
{
popped = Pop();
return true;
}
}
public bool IsEmpty() => root == null ? true : false;
public void Clear()
{
root = null;
}
}
}

Dynamic derive Generic Type Parameter

I am using a recursive function for a object tree. That is, my object collection is like:
Object1
--Object2
----Object3
------Object4
All objects inherits from a base object (abstract class), where has a Validate() method, and its collection inherits from ITreeCollection. I have written a recursive function to perform that:
private bool Validate<T>(ITreeCollection items) where T : TreeNodeBase
{
foreach (var itm in items as Collection<T>)
{
if (((TreeNodeBase)itm).Items != null)
{
return Validate<T>(((TreeNodeBase)itm).Items);
}
else return true;
}
return true;
}
How can I derive the the type parameter T for the inner function (i.e. return Validate<T>(((TreeNodeBase)itm).Items))
Firstly, as it stands, you are not using the type parameter T so it could safely be removed. However I imagine you might want to do some type specific validation so this is perhaps not that helpful a suggestion. But, without example of what you want to do with T it's difficult to make suggestions.
Anyhow, here's one approach of what I think you are trying to do:
private bool Validate(ITreeCollection items)
{
foreach (TreeNodeBase node in (IEnumerable) items)
{
// validate the node itself first
if (!Validate(node))
{
return false;
}
if (node.Items != null)
{
// validate its children
if (!Validate(node.Items)
{
return false;
}
}
}
return true;
}
private bool Validate(TreeNodeBase node)
{
if (node is BananaNode)
{
var bananaNode = (BananaNode) node;
//TODO do BananaNode specific validation
}
else if (node is AppleNode)
{
var appleNode = (AppleNode) node;
//TODO do AppleNode specific validation
}
else
{
throw new ArgumentOutOfRangeException("Cannot validate node of type '" + node.GetType().Name + "'.");
}
}
You could get snazzy with the dynamic keyword and get rid of some of this type checking but it does get a bit confusing and I'd advise against it:
private bool Validate(ITreeCollection items)
{
foreach (TreeNodeBase node in (IEnumerable) items)
{
// validate the node itself first
if (!Validate((dynamic) node)) // this will call the most appropriate version of Validate
{
return false;
}
if (node.Items != null)
{
// validate its children
if (!Validate(node.Items)
{
return false;
}
}
}
return true;
}
private bool Validate(BananaNode node)
{
//TODO do BananaNode specific validation
}
private bool Validate(AppleNode node)
{
//TODO do AppleNode specific validation
}
private bool Validate(TreeNodeBase node)
{
throw new ArgumentOutOfRangeException("Cannot validate node of type '" + node.GetType().Name + "'.");
}

Categories

Resources