I am trying to learn the basics of data algorithms in C# and when implementing the below binary search tree add in process I get stuck at understanding the following: when calling the tree1.add(20); method, on the first iteration of the while loop the current.Data has the value of 50 and on the second iteration of the loop the value of the same current.Data changes to 40.
Why the value of the current.Data doesn't stuck at the value of 50 after the first iteration and what is the process by which the current.Data receives the value of 40?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BinarySearchTree
{
public class Node
{
public int Data;
public Node LeftChild;
public Node RightChild;
}
public class BinarySearchTree
{
public Node root;
public BinarySearchTree()
{
root = null;
}
public void add(int data)
{
Node newNode = new Node();
newNode.Data = data;
if (root == null)
{
root = newNode;
}
else
{
Node current = root;
Node parent;
while (true)
{
parent = current;
if (data < current.Data)
{
current = current.LeftChild;
if (current == null)
{
parent.LeftChild = newNode;
break;
}
}
else
{
current = current.RightChild;
if (current == null)
{
parent.RightChild = newNode;
break;
}
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
BinarySearchTree tree1 = new BinarySearchTree();
tree1.add(50);
tree1.add(40);
tree1.add(60);
tree1.add(20);
tree1.add(45);
tree1.add(55);
tree1.add(65);
Console.ReadLine();
}
}
}
The answer lays here:
while (true)
{
parent = current;
if (data < current.Data)
{
current = current.LeftChild; // THIS LINE
if (current == null)
{
parent.LeftChild = newNode;
break;
}
}
As you see, current is being revalued and now it is the left "child" of it self. After the first 3 add usages, the tree should look like this:
50
/ \
40 60
So first iteration - current is 50, second iteration , it goes to the left(definition of a BST) and it becomes 40 . The next iteration current will contain NULL , (The left child of 40) and will be placed inside the BST.
Related
I'm attempting to create a binary search tree without using a recursion to walk through the tree. The code attached works for initializing the tree, but when I try to walk through it, it keeps giving me the "object reference not set to instant of object" when trying to push to the stack in the GetEnumerator() method. I realize that this means I need to push an instance instead of the class itself, but how can I make an instance of "this", so to speak? Or is the only way to implement with stack is to create a separate class that holds the tree? The code is as below:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class BinarySearchTree : IEnumerable<int>
{
public int value;
public BinarySearchTree left;
public BinarySearchTree right;
Stack<BinarySearchTree> stacks;
public BinarySearchTree(int value)
{
this.value = value;
}
public BinarySearchTree(IEnumerable<int> values)
{
this.value = values.First();
foreach (var val in values.Skip(1))
{
this.Add(val);
}
}
public int Value
{
get
{
return this.value;
}
}
public BinarySearchTree Left
{
get
{
return this.left;
}
}
public BinarySearchTree Right
{
get
{
return this.right;
}
}
public void Add(int value)
{
BinarySearchTree current_node = this;
while (current_node.left != null && current_node.right != null)
{
if (value <= current_node.value)
{
current_node = current_node.left;
}
else
{
current_node = current_node.right;
}
}
if (value <= current_node.value)
{
current_node.left = new BinarySearchTree(value);
//return current_node;
}
else
{
current_node.right = new BinarySearchTree(value);
//return current_node;
}
}
public BinarySearchTree GetValueAtNode()
{
}
public IEnumerator<int> GetEnumerator()
{
BinarySearchTree current_node = this;
stacks.Push(current_node);
while (stacks.Count != 0){
if (current_node.left != null)
{
stacks.Push(current_node);
current_node = current_node.left;
}
yield return stacks.Peek().value;
current_node = stacks.Peek().right;
stacks.Pop();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The error message is:
BinarySearchTreeTests.Can_sort_complex_tree:
Outcome: Failed
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at BinarySearchTree.GetEnumerator()+MoveNext() in c:\Users\320145763\Exercism\csharp\binary-search-tree\BinarySearchTree.cs:line 78
at BinarySearchTreeTests.Can_sort_complex_tree() in c:\Users\320145763\Exercism\csharp\binary-search-tree\BinarySearchTreeTests.cs:line 84
And the relevant unit test is:
using System.Linq;
using Xunit;
public class BinarySearchTreeTests
{
[Fact]
public void Can_sort_complex_tree()
{
var tree = new BinarySearchTree(new[] { 2, 1, 3, 6, 7, 5 });
Assert.Equal(new[] { 1, 2, 3, 5, 6, 7 }, tree.AsEnumerable());
}
}
Some issues:
The while condition in Add is not correct, it could be that just one child reference is null and that the code that follows the while loop will overwrite the existing child reference, whereby you will potentially lose part of the tree. It is probably easiest to do a while (true) and break out of the loop as soon as in the direction of choice there is no child and a new node is created to fill that gap.
stacks should not be an instance member, but a variable local to GetEnumerator as otherwise you will get two executing GetEnumerator iterators to interfere which each other's stack needs.
stacks is never initialised to be an actual Stack instance. You need new Stack<BinarySearchTree>() somewhere...
The logic of GetEnumerator is not (entirely) correct. For instance current_node = stacks.Peek().right; may assign null to current_node so that you get an exception in the next iteration.
Here is a correction to the two impacted methods:
public void Add(int value)
{
BinarySearchTree current_node = this;
while (true)
{
if (value <= current_node.value) {
if (current_node.left == null) {
current_node.left = new BinarySearchTree(value);
break;
}
current_node = current_node.left;
} else {
if (current_node.right == null) {
current_node.right = new BinarySearchTree(value);
break;
}
current_node = current_node.right;
}
}
}
public IEnumerator<int> GetEnumerator()
{
Stack<BinarySearchTree> stacks = new Stack<BinarySearchTree>();
stacks.Push(this);
while (stacks.Count != 0){
BinarySearchTree current_node = stacks.Peek();
while (current_node.left != null) {
current_node = current_node.left;
stacks.Push(current_node);
}
while (stacks.Count != 0){
current_node = stacks.Peek();
yield return current_node.value;
stacks.Pop();
if (current_node.right != null) {
stacks.Push(current_node.right);
break;
}
}
}
}
I have created a simple list class from scratch. This is for a class assignment that I have been working on for about a week - very new to lists. We can not use generics so trying to research my question below has not been fruitful. Although I did get to watch 7 tutorials on youtube by BetterCoder and I found some stuff in my book but nothing with an example of "merging".
I have three classes - my node, my list, and my program. In my list class, I am working on building a Merge() method which eventually will compare the data in the two lists and merge them into an ordered list.
Right now for some reason my Merge method - which is very basic to help me understand what is happening - is not working correctly. It has both lists passed to it, and is adding the data from listTwo to listOne BUT for some reason when it's printing to the console the second Node's Data shows twice :
EX: 1 -> 2 -> 2
instead of printing the head (1), the next (2) and then the next (3) which it should be.
EX: 1 -> 2 -> 3
In the program class I have proven with a write line that (listOne.firstNode.Next.Next.Data) = 3 . Which it should be.
Can someone help me figure out if the nodes in list one aren't pointing to each other correctly or whatever is going on?
My Merge Method must be passed both list objects (listOne and listTwo) and eventually I need to make those passed as references but I haven't figured that out quite yet and will focus on that later I suppose.
namespace LinkedList
{
//This is my Node Class
class Node
{
public object Data { get; set; }
public Node Next { get; set; }
public Node(object dataValue) : this(dataValue, null) { }
public Node(object dataValue, Node nextNode)
{
Data = dataValue;
Next = nextNode;
}
}
//This is my List Class
class List
{
public Node firstNode;
public int count;
public List()
{
firstNode = null;
}
public bool Empty
{
get { return this.count == 0; }
}
public int Count
{
get { return this.count; }
}
public object Add(int index, object o)
{
if (index < 0)
throw new ArgumentOutOfRangeException("Index: " + index);
if (index > count)
index = count;
Node current = this.firstNode;
if (this.Empty || index == 0)
{
this.firstNode = new Node(o, this.firstNode);
}
else
{
for (int i = 0; i < index - 1; i++)
current = current.Next;
current.Next = new Node(o, current.Next);
}
count++;
return o;
}
public object Add(object o)
{
return this.Add(count, o);
}
public object Merge(List a, List b)
{
a.Add(b.firstNode.Data);
return a;
}
public void Print()
{
while (this.count > 0)
{
Console.Write(firstNode.Data + "->");
if(firstNode.Next != null)
firstNode.Data = firstNode.Next.Data;
count--;
}
}
}
//And here is my Program
class Program
{
static void Main(string[] args)
{
List listOne = new List();
List listTwo = new List();
listOne.Add(1);
listOne.Add(2);
listTwo.Add(3);
listTwo.Print();
Console.WriteLine("");
listOne.Merge(listOne, listTwo);
Console.WriteLine("");
listOne.Print();
//This line below shows that the data "3" from listTwo is being added to listOne in the list Merge Method
//Console.WriteLine(listOne.firstNode.Next.Next.Data);
Console.ReadKey();
}
}
}
Actual problem in your print method
public void Print()
{
Node node = firstNode;
for (int i = 0; i < this.count; i++)
{
Console.Write(node.Data + "->");
if (node.Next != null)
node = node.Next;
}
}
Alex Sikilinda , you are right the merge method is incomplete.
public object Merge(List a, List b)
{
Node bNode = b.firstNode;
while (bNode != null)
{
a.Add(bNode.Data);
bNode = bNode.Next;
}
return a;
}
I would write it this way:
public void Merge(List b)
{
Node lastNode = GetLastNode();
if (lastNode != null)
{
lastNode.Next = b.firstNode;
}
else
{
this.firstNode = b.firstNode;
}
}
// this method is used to find the last node in current list
private Node GetLastNode()
{
if (this.firstNode == null)
{
return null;
}
Node current = this.firstNode;
while (current.Next != null)
{
current = current.Next;
}
return current;
}
First of all, I changed signature of Merge from public object Merge(List a, List b) to public void Merge(List b). Now we can use it like this:
listOne.Merge(listTwo);
This will link listOne's last element with the first element of listTwo and thus they are merged.
Now we need to change Print method since current version modifies the list, which shouldn't happen:
public void Print()
{
Node currentNode = this.firstNode;
while(currentNode != null)
{
Console.Write(currentNode.Data + ' ');
currentNode = currentNode.Next;
}
}
Instead of assigning the data back to first node I assign the
firstNode = firstNode.Next;
Please check the below Print Code
public void Print()
{
while (this.count > 0)
{
Console.Write(firstNode.Data + "->");
if (firstNode.Next != null)
firstNode = firstNode.Next;
count--;
}
}
i didn't succeed to remove specific item from linked list,the method is - public void removeFromList(string itemtoremove, LinkedList List).
How do i write method that removes specific item from linked list?
my code is:
public class Node
{
public Node next; //saves the adress
public Person data; //saves the person
}
public class LinkedList
{
private Node head; //starts from the begging
public void AddFirst(Person data)
{
Node toAdd = new Node();
toAdd.data = data; // in data he saves the object
toAdd.next = head;
head = toAdd;
}
public void removeFromList(string itemtoremove, LinkedList List) //
{
Node current = head;
Node current1 = current.next;
while (current1 != null)
{
if (current1.data.instrument == itemtoremove)
???
}
}
}
Your method already has a problem before you even implement the algorithm. You are skipping the head node. You also don't need to pass the linked list in as a parameter to the instance method.
public void removeFromList(string itemtoremove)
{
Node previousNode = null;
Node current = head;
while (current != null) //starting with current1 would ignore the head node
{
// we found a match
if (current.data.instrument == itemtoremove){
// head node is treated slightly differently
if(current == head){
// set the next node to the new head
head = current.next;
// set to null so GC can clean it up
current = null;
return;
}
else {
//update the previous node's link
previousNode.next = current.next;
current = null;
return;
}
}
// move on to the next
previousNode = current;
current = current.next;
}
}
In the interview question, "Implement an algorithm which detects for presence of the loop.". For example, the linked list has a loop, like:
0--->1---->2---->3---->4---->5---->6
▲ |
| ▼
11<—-22<—-12<—-9<—-8
Using Floyd's cycle detection, this problem can be solved by using a fast & slow pointer. So should I try comparing
a. Link's node values, i.e.
if (fast.data == slow.data)
break;
where fast and slow are of type Link
class Link
{
int IData {get; set;}
Link Next {get; set;}
}
OR
b. Are they pointing to same reference, i.e. if (fast == slow)
Thanks.
You should only be comparing the nodes themselves. After all, it's reasonable to have a linked list with repeated data in, without it actually having a cycle.
I would call them nodes rather than links too. A link is simply the reference from one node to the next or previous one - in particular, there's no data associated with a link, only with a node.
Hope this helps... It might be naive but it works...
using System;
namespace CSharpTestTemplates
{
class LinkedList
{
Node Head;
public class Node
{
public int value;
public Node NextNode;
public Node(int value)
{
this.value = value;
}
}
public LinkedList(Node head)
{
this.Head = head;
}
public Boolean hasLoop()
{
Node tempNode = Head;
Node tempNode1 = Head.NextNode;
while(tempNode!=null && tempNode1!=null){
if(tempNode.Equals(tempNode1)){
return true;
}
if ((tempNode1.NextNode != null) && (tempNode.NextNode != null))
{
tempNode1 = tempNode1.NextNode.NextNode;
tempNode = tempNode.NextNode;
}
else
{
return false;
}
}
return false;
}
public static void Main()
{
Node head = new Node(1);
LinkedList ll = new LinkedList(head);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
head.NextNode = node2;
node2.NextNode = node3;
node3.NextNode = node4;
node4.NextNode = node5;
node5.NextNode = node6;
node6.NextNode = null;
Console.WriteLine(ll.hasLoop());
Console.Read();
}
}
}
I am having a problem with selecting a certain child node.
What I want to achieve: I you have this treeview for example (one parent with two child nodes): Parent -Child with a value 5 -Child with a value 2.
I want to add these two values and assign them to Parent node: Parent result 7 -Child 5 -Child 2.
Of course, a bigger treeview would have several parents and lots of children and they will all add up to one root node.
How can I do this?? pls help.
thx, Caslav
You could do something like the following. It assumes the value you want is part of the text (the last value after the last space).
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace TreeViewRecurse
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
RecurseTreeViewAndSumValues(treeView1.Nodes);
}
public void RecurseTreeViewAndSumValues(TreeNodeCollection treeNodeCol)
{
int tree_node_sum = 0;
foreach (TreeNode tree_node in treeNodeCol)
{
if (tree_node.Nodes.Count > 0)
{
RecurseTreeViewAndSumValues(tree_node.Nodes);
}
string[] node_split = tree_node.Text.Split(' ');
string num = node_split[node_split.Length - 1];
int parse_res = 0;
bool able_to_parse = int.TryParse(num, out parse_res);
if (able_to_parse)
{
tree_node_sum += parse_res;
}
}
if (treeNodeCol[0].Parent != null)
{
string[] node_split_parent = treeNodeCol[0].Parent.Text.Split(' ');
node_split_parent[node_split_parent.Length - 1] = tree_node_sum.ToString();
treeNodeCol[0].Parent.Text = string.Join(" ", node_split_parent);
}
}
}
}
private TreeNode SearchTree(TreeNodeCollection nodes, string searchtext)
{
TreeNode n_found_node = null;
bool b_node_found = false;
foreach (TreeNode node in nodes)
{
if (node.Tag.ToString() as string == searchtext)
{
b_node_found = true;
n_found_node = node;
}
if (!b_node_found)
{
n_found_node = SearchTree(node.Nodes, searchtext);
}
}
return n_found_node;
}
Source:
http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_21895513.html
I used a modified version of Redburn's answer to find a treenode by name:
private TreeNode GetNodeByName(TreeNodeCollection nodes, string searchtext)
{
TreeNode n_found_node = null;
bool b_node_found = false;
foreach (TreeNode node in nodes)
{
//show(node.Name + ":" +searchtext);
if (node.Name == searchtext)
{
//show("score!");
b_node_found = true;
n_found_node = node;
return n_found_node;
}
if (!b_node_found)
{
//show("here");
n_found_node = f_get_node_by_name(node.Nodes, searchtext);
if (n_found_node!=null)
{
return n_found_node;
}
}
}
return null;
}
Dunno if this matches your request, but this will add all childs > parent node
private void button2_Click(object sender, EventArgs e)
{
int grandTotal = CalculateNodes(this.treeView1.Nodes);
}
private int CalculateNodes(TreeNodeCollection nodes)
{
int grandTotal = 0;
foreach (TreeNode node in nodes)
{
if (node.Nodes.Count > 0)
{
int childTotal = CalculateNodes(node.Nodes);
node.Text = childTotal.ToString();
grandTotal += childTotal;
}
else
{
grandTotal += Convert.ToInt32(node.Text);
}
}
return grandTotal;
}
you should do some error checking etc etc to make it solid
You could inherit from TreeNode with something like this:
public class TreeNodeEx : TreeNode {
// only displayed when having no children
public int Value { get; set; }
public bool HasChildren {
get { return Nodes.Count > 0; }
}
public int GetSumOfChildren() {
if (!HasChildren)
return Value;
var children = Nodes.Cast<TreeNode>().OfType<TreeNodeEx>();
int sum = 0;
foreach (var child in children)
sum += child.GetSumOfChildren();
return sum;
}
}
Like this:
public class TotalingTreeNode : TreeNode
{
private int _value = 0;
public int Value
{
get
{
if (this.Nodes.Count > 1)
return GetTotaledValue();
else
return _value;
}
set
{
if (this.Nodes.Count < 1)
_value = value;
}
}
private int GetTotaledValue()
{
foreach (TotalingTreeNode t in this.Nodes.Cast<TotalingTreeNode>())
{
_value += t.Value;
}
return _value;
}
}
In WinForms a childnode of a tree knows its Parent. So you can reach the parent at any time using the TreeNode.Parent property. Vice versa every Node knows it's child nodes. You can reach them using Node.Nodes. This collection has an indexer that allows you to access the child nodes using an int or a string.
To find a TreeNode with a special Key use the following code:
treeView.Nodes.Find("nodeKey", true);
You can finde a description of this method at MSDN