I am trying to delete a node from a binary tree using c#. This example only works if the node has no children. I understand how the deletion works with children, but I'm getting hung up on an issue that seems to me to be from a lack of understanding of c#:
public class Tree
{
internal class Node
{
public int Val { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
public Node(int val)
{
Val = val;
}
}
private Node root;
public void Delete(int val)
{
Node current = this.root;
Node parent = null;
while (true) {
if (val < current.Val) {
parent = current;
current = current.Left;
}
else if (val > current.Val) {
parent = current;
current = current.Right;
}
else if (val == current.Val) {
current = null;
return;
}
}
}
}
My issue is in the line where I set current = null. The way I'm intending to use this, is to use current = null to delete the current node. But it doesn't work. if I reference the current node from the parent:
parent.Right = null;
the node is properly deleted, but is obviously a pain because I need to check if the current node is the right or left child of the node. What am I missing? Thanks in advance!
You cannot do this.
The current variable is a separate variable from the parent.Left or parent.Right variables.
When you do this:
current = parent.Left;
you're copying the value of the variable, you're not linking one variable to another. You can liken this to postit notes. On one postit note you have an address, then you execute the above statement and copy the address onto another postit note. Changing the copy afterwards does not in any way or shape change the original note.
So yes, you need to keep track of which child reference variable you got current from.
Related
Can someone please explain how a locally initialized object in this case "root, is able to have Left and Right properties assigned with Node objects in previous recursion stages, without passing root as function argument.
I suspect this effect is due to return statement returning Node object reference in previous Recursion stages.
However, my understanding is that return statement is simply ending function call by removing function from Stack, only the "first original" function before any recursion started will return actual value.
Codes in C#
private Node<int> TestLocalVariableRecursion(int start)
{
Node<int> root = null;
if(start < 5)
{
root = new Node<int>(start);
root.Left = TestLocalVariableRecursion(start + 1);
root.Right = TestLocalVariableRecursion(start + 2);
}
return root;
}
public class Node<T>
{
public Node(T value)
{
Value = value;
}
public T Value { get; set; }
public Node<T> Left { get; set; }
public Node<T> Right { get; set; }
}
result of root: https://i.stack.imgur.com/qdJqQ.png
I am trying to add tree branch to IDictionary<int,Division> where int is depth of object and object shown below.
Example of dictionary result:
0, Parent
1, Parent.Child
2, Parent.Child.Child
class Division
{
public int Id { get; set; }
public int ParentId { get; set; }
public Division Parent { get; set; }
public ICollection<Division> Children { get; set; }
}
I am using recursion to iterate from root parent to child I need and at the same moment adding depth and Division to dictionary.
For iteration I am using this method.
public void GetBranchFromTop(Division division, int selectedNodeId, int selectedNodeDepth, ref IDictionary<int, Division> branch)
{
branch.Add(selectedNodeDepth, division);
if (division.Id == selectedNodeId)
{
return;
}
if (division.Children != null)
{
foreach (var child in division.Children)
{
selectedNodeDepth = selectedNodeDepth + 1;
GetBranchFromTop(child, selectedNodeId, selectedNodeDepth, ref branch);
}
}
}
This method works fine when object have only one child. When there is more children adding to dictionary is impossible because of depth key is repeating.
I figured that I need to add objects to dictionary only after finding object I am searching but nothing comes to mind how can I do it recursively.
I can think of 2 ways of doing it. First, you'll need have a separate branch dictionary for each tree branch - meaning for each call of GetBranchFromTop, like this
public void GetBranchFromTop(
Division division,
int selectedNodeId,
int selectedNodeDepth,
ref IDictionary<int, Division> foundBranch,
IDictionary<int, Division> currentBranch)
{
if(foundBranch != null){
return; //no need to continue search if the target branch was found already
}
currentBranch.Add(selectedNodeDepth, division);
if (division.Id == selectedNodeId)
{
foundBranch = currentBranch;
return;
}
if (division.Children != null)
{
var nextNodeDepth = selectedNodeDepth + 1;//note this is moved out of the loop
foreach (var child in division.Children)
{
var newBranch = new Dictionary<int, Division>(currentBranch); //copy the branch for each child.
GetBranchFromTop(child, selectedNodeId, nextNodeDepth, ref foundBranch, newBranch);
}
}
}
Note that you had an error in selectedNodeDepth = selectedNodeDepth + 1; - it was inside the loop, meaning it will be incremented for all the children, who are at the same +1 depth.
The second way where you don't need to drag all the branches around: you need to find Division you are looking for in the tree, say its targetDivision. When you've got it, build its tree branch using Parent links:
List<Division> parentsAndSelf = new List<Division>();
Division currentDivision = targetDivision;
while(currentDivision != null){
parentsAndSelf.Add(currentDivision);
currentDivision = currentDivision.Parent;
}
parentsAndSelf = parentsAndSelf.Reverse();
Now parentsAndSelf list will contain the desired Parent -> Child -> Child.Child list with target Division at the end. The depth will be the index of an item in the list.
I just started using c# again and now I have a strange problem with my parameters.
I tried to build a List by my self.
So I have:
class NodeList
{
public Node FirstCity { get; set; }
public Node findNode(String name)
{
//...stuff
}
}
And This:
class Node
{
public String Name {get; set;}
public Node next {get; set;}
}
So, in my project I (lets say on button click) create a new Nodelist.
(By default I have already a few nodes in it.)
Now I do this:
Node n = nodelist.findNode("test");
and then I have another class I called tool.
tool.doSomething(n , nodelist);
Now the strange thing is that, when I look at nodelist, when I call the above the list is correct. The doSomething method, doesn´t even call the nodelist but it changes it.
doSomething(n, list)
{
NodeList nl = new NodeList();
nl.Add(n);
//other stuff
}
At the point where I change the new List for some reason the other list, which is in a different class, changes too.
Can anyone please explain why and how I can fix this!?
Edit:
This is my Add Method:
Add(Node node){
node.next = null;
Node current = FirstCity;
if (current == null)
FirstCity = node;
else
{
while (current.next != null)
{
current = current.next;
}
current.next = node;
}
}
I have the following class which recurs on itself to form a tree-like data structure:
public class chartObject
{
public string name { get; set; }
public int descendants { get; set; }
public List<chartObject> children { get; set; }
}
For each object in the tree I would like to populate the descendant property with the amount objects that exist underneath it.
Example structure:
chartObject1 (descendants: 4)
└-chartObject2 (descendants: 0)
└-chartObject3 (descendants: 2)
└--chartObject4 (descendants: 1)
└---chartObject5 (descendants: 0)
What would be the most efficient way of doing this?
How about the recursive formula:
children.Count + children.Sum(c => c.descendants)
This is suitable for eager-evaluation / caching if the tree is immutable (which it isn't from the class declaration). If you want efficiency even in the face of mutability, you'll find this a lot more difficult; you can consider marking parts of the tree "dirty" as it is mutated / eagerly force the re-evalutation of this metric to "bubble up" as part of a tree is mutated.
This works for me:
public void SetDescendants(chartObject current)
{
foreach (var child in current.children)
{
SetDescendants(child);
}
current.descendants = current.children.Sum(x => 1 + x.descendants);
}
I tested with this code:
var co = new chartObject()
{
name = "chartObject1",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject2",
children = new List<chartObject>() { }
},
new chartObject()
{
name = "chartObject3",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject4",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject5",
children = new List<chartObject>() { }
}
}
}
}
}
}
};
And got this as the result:
For calculations to be most efficient, cache their result in the node itself. Otherwise, you'll be re-calculating the count every time the descendants property is looked up.
The cost of doing that is the need to invalidate the cache all the way up the parent chain, like this:
public class chartObject
{
private chartObject _parent;
private int? _descCache = null;
public string name { get; set; }
public int descendants {
get {
return _descCache ?? calcDescendents();
}
}
public List<chartObject> children { get; set; }
public void AddChild(chartObject child) {
child._parent = this;
children.Add(child);
chartObject tmp = this;
while (tmp != null) {
tmp._descCache = null;
tmp = tmp._parent;
}
}
private int calcDescendents() {
return children.Count+children.Sum(child => child.descendants);
}
}
Walk all nodes of the tree (depth first is ok) and when done with children set "descendants property to sum of children's descendants + child count. You have to do it on every change to the tree structure. You should be able to limit updates only to parents of element that is changed.
If nodes made immutable you can populate the field at creation time.
Side notes:
Your tree is mutable as it is now (one can easily add more child nodes anywhere), so it may be safer to have method that counts descendants instead of property on a node.
Having computed property int descendants { get; set; } to be read/write is confusing as anyone can set its value to whatever number. Consider if making it read only and updating when one of child nodes changes (requires some custom notification mechanism).
Code style - consider naming classes with upper case names for code that is intended to be public (follow Microsoft's C# coding guidelines). chartObject -> ChartObject
Im working with simple linked lists in C# and I have no idea how to add elements at the end of the list, colud anyone helpme?
namespace ConsoleApplication1
{
class Class1
{
public class Node()
{
public int Data;
public Node Next;
}
private Node FirstNode=null;
public void AddBefore(int number)
{
Node NewNode=new Node();
NewNode.Next=FirstNode;
NewNode.Data=number;
FirstNode=NewNode;
}
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
???????????????
}
}
}
}
You need to iterate through your list until you find the last node, and then add it to the end. Something like:
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
// Finding the last node
Node currentNode = FirstNode;
while (currentNode.NextNode != null)
currentNode = currentNode.NextNode;
// Constructing a new node
Node newNode = new Node();
newNode.Data = number;
newNode.Next = null;
// Adding the new node to the end
currentNode.NextNode = newNode;
}
}
else
{
Node NewNode=new Node();
NewNode.Data=number;
Node LastNode = GetLastNode();
LastNode.Next = NewNode;
}
You'll still have to implement GetLastNode or else you wont practise anything =P
The question is kind of confusing. Are you asking how to place a node at the end of the list, or as the next item in the list.
I had to do this for a homework assignment way back in the day (it was java though). If you want to always add a node to the end of the list then you also need to edit your list class to contain a head and tail of the list. This will allow you to add items to the end or beginning.
If you want to always add a node to the end then you could try editing the code so that when you add a node to the end the previous node's next node value will be set to the tail instead of null. This will always allow for you to add an item to the end of the list (which is what most add methods do unless a position is specified anyways)
In short:
Add Node tailNode = null; to Class and add a method that will get and set the next node for the Node class. Once this is done, then edit the code so that it looks something like this:
class Class1
{
public class Node()
{
public int Data;
public Node Next;
//Class to set next node
public void setNext(Node nextNode)
{
//Set next node
Next = nextNode;
}
//Get next node
public Node getNext()
{
return Next;
}
}
private Node FirstNode=null;
private Node lastNode = null;
public void AddBefore(int number)
{
Node NewNode=new Node();
NewNode.Next=FirstNode;
NewNode.Data=number;
FirstNode=NewNode;
}
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
if(FirstNode.getNext() == null)
{
//No tail. Make this node tail
lastNode = new Node();
lastNode.Data = number;
//Set first node's next to last node
FirstNode.setNext(lastNode);
}else{ //TailNode already set
//New node to be tail
Node newLastNode = new Node();
newLastNode.Data = number;
//Set the current tail node to have this node as next
lastNode.setNext(newLastNode);
//Make new last node last node
lastNode = newLastNode;
}
}
}
}
The code may be a little off (I haven't really tested it) but that is the main picture of what you are going to have to do.