I have a binary tree written in c# with nodes defined with IComparable data. It all works just fine in the sense that I can populate the tree with any data type I like (although I've only tried populating it with a single type of data at a time) and perform functions like finding the depth, in-order searching, counting leaves, etc.
I'm trying to write a function to find a data value in the tree using a recursive algorithm. The algorithm finds the data, but then does not stop when the data is found. There is one exception -- when the data is in the root node. I can't figure out where it is going wrong. The function reports that it found the data, at which point it is supposed to return that node and quit, but it keeps going looking in the children nodes.
Thanks to the accepted answer, here is the working code I have:
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
if (node == null)
{
return null;
}
int test = value.CompareTo(node.data);
if (test < 0)
{
return findValueStartingAtNode(node.left_child, value);
}
else if (test > 0)
{
return findValueStartingAtNode(node.right_child, value);
}
else
{
return node;
}
}
Code:
public TreeNode findValue(IComparable value)
{
TreeNode node = findValueStartingAtNode(this.root, value);
if (node == null)
{
Console.WriteLine("value not found");
return null;
}
else
{
return findValueStartingAtNode(this.root, value);
}
}
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
Console.WriteLine("looking for value {0}", value);
if (node == null)
{
Console.WriteLine("node is null -- returning null");
return null;
}
else if (value.CompareTo(node.data) == 0)
{
Console.WriteLine("value found at current node");
Console.WriteLine("current node data is {0}", node.data);
Console.WriteLine("done and returning node");
return node;
}
else
{
Console.WriteLine("checking children");
TreeNode left = findValueStartingAtNode(node.left_child, value);
TreeNode right = findValueStartingAtNode(node.right_child, value);
Console.WriteLine("the values are left: {0}, right: {1}", left.data, right.data);
if (value.CompareTo(left.data) == 0)
{
Console.WriteLine("value found in left child");
return left;
}
else if (value.CompareTo(right.data) == 0)
{
Console.WriteLine("value found in right child");
return right;
}
else
{
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
}
Output:
C:\Users\abalter\Documents\CS273\TreeNode\TreeNode\bin\Debug>TreeNode.exe
looking for value 50
value found at current node
current node data is 50
done and returning node
looking for value 50
value found at current node
current node data is 50
done and returning node
(in main) value 50 found
looking for value 45
checking children
looking for value 45
value found at current node
current node data is 45
done and returning node
looking for value 45
checking children
looking for value 45
checking children
looking for value 45
node is null -- returning null
looking for value 45
checking children
looking for value 45
node is null -- returning null
looking for value 45
node is null -- returning null
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 220
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 218
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 217
at TreeNode.BinaryTree.findValueStartingAtNode(TreeNode node, IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 218
at TreeNode.BinaryTree.findValue(IComparable value) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\BinaryTree.cs:line 186
at TreeNode.Program.Main(String[] args) in c:\Users\abalter\Documents\CS273\TreeNode\TreeNode\Program.cs:line 36
C:\Users\abalter\Documents\CS273\TreeNode\TreeNode\bin\Debug>
A Binary Search Tree has certain properties. The property that's important here is that for each node, everything in that node's left subtree is smaller than the node's value and everything in its right subtree is larger (according to the comparer).
You only ever have to look in one subtree. Use that property to find the item you're looking for:
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
if (node == null) return null;
int comp = value.CompareTo(node.data);
if (comp == 0) return node; //Found it
if (comp < 0) return findValueStartingAtNode(node.left_child, value); //The item must be in the left subtree
return findValueStartingAtNode(node.right_child, value); // The item must be in the right subtree
}
Bonus: instead of a recursive method, here's an iterative Search function from my own implementation: (It's also generic)
private BinaryTreeNode<T> Search(BinaryTreeNode<T> node, T item)
{
if (node == null) return null;
int c;
while (node != null && (c = comparer.Compare(item, node.Value)) != 0)
node = c < 0 ? node.Left : node.Right;
return node;
}
Instead of looking down the left and right, then checking to see if it was found you should look down the left only. If it is found there, return that, otherwise look down the right. If it is there, return that, otherwise return null. Your else would look something like this:
Console.WriteLine("checking children");
TreeNode left = findValueStartingAtNode(node.left_child, value);
if (left != null && value.CompareTo(left.data) == 0)
{
Console.WriteLine("value found in left child");
return left;
}
else
{
TreeNode right = findValueStartingAtNode(node.right_child, value);
if (right != null && value.CompareTo(right.data) == 0)
{
Console.WriteLine("value found in right child");
return right;
}
else
{
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
findValueStartingAtNode should be returning either null if the value isn't found or the correct TreeNode if the value is found. There's no reason to do a comparison of the values of the right and left child nodes, because the recursive call on the children nodes will check the value of the children on its own. It will also fail and throw a NullReferenceException whenever a node is encountered without both children. Lastly, your findValue call is searching the tree twice.
I would replace your code with this:
public TreeNode findValue(IComparable value)
{
TreeNode node = findValueStartingAtNode(this.root, value);
if (node == null)
{
Console.WriteLine("value not found");
}
return node;
}
private TreeNode findValueStartingAtNode(TreeNode node, IComparable value)
{
Console.WriteLine("looking for value {0}", value);
if (node == null)
{
Console.WriteLine("node is null -- returning null");
return null;
}
else if (value.CompareTo(node.data) == 0)
{
Console.WriteLine("value found at current node");
Console.WriteLine("current node data is {0}", node.data);
Console.WriteLine("done and returning node");
return node;
}
else
{
Console.WriteLine("checking left child");
TreeNode left = findValueStartingAtNode(node.left_child, value);
if(left != null) return left;
Console.WriteLine("checking right child");
TreeNode right = findValueStartingAtNode(node.right_child, value);
if(right != null) return right;
Console.WriteLine("value not found in either child");
Console.WriteLine("current node data is {0}", node.data);
return null;
}
}
It should also be mentioned that this doesn't qualify as a binary search tree. It will perform a depth-first search, ending only when the value is found or the entire tree has been visited.
That seems...complicated to me, what with the double calls and all.
It's important to note that every node of a tree is itself a tree. There's no difference between the root node of the tree and any other node of the tree. You just have to do the walk once. Like many recursive problems, the tree walk has two cases:
The special case: The tree is empty (null).
The general case: The tree is non-empty.
Consequently, the tree walk logic is this:
The Special Case. If the root (current) node is null, the search failed. return null.
The General Case. Compare the root (current) node's payload to the desired value.
EQUAL: A Hit! Return the root (current) node.
LESS THAN: A miss. Return the results of visiting the left child.
GREATER THAN: A miss. Return the results visiting the right child.
That's all there is to it. Given a node structure like this:
public class TreeNode<T> where T:IComparable
{
public TreeNode<T> Left { get ; set ; }
public TreeNode<T> Right { get ; set ; }
public T Payload { get ; set ; }
}
The tree search code shouldn't be much more difficult than this
public TreeNode<T> FindNodeWithValue( IComparable value )
{
Func<IComparable,int> compareToDesiredValue = (x) => x.CompareTo(value) ;
TreeNode<T> node = FindNodeWithValue( this.Root , compareToDesiredValue ) ;
return node ;
}
private TreeNode<T> FindNodeWithValue( TreeNode<T> root , Func<IComparable,int> compareToDesiredValue )
{
TreeNode<T> result = null ;
if ( root != null )
{
int cc = compareToDesiredValue( root.Payload ) ;
switch ( cc )
{
case 0 : result = root ; break ;
case -1 : result = FindNodeWithValue( root.Left , compareToDesiredValue ) ; break ;
case +1 : result = FindNodeWithValue( root.Right , compareToDesiredValue ) ; break ;
default : throw new InvalidOperationException() ;
}
}
return result ;
}
Further, given that this search is directed, so you've got no need to keep track of parent nodes and no need to be able to backtrack on alternatives, the code can easily be iterative and as simple as this:
public TreeNode<T> FindNodeWithValue( IComparable value )
{
TreeNode<T> current = this.Root ;
int cc ;
while ( current != null && 0 != (cc=current.Payload.CompareTo(value)) )
{
// if we land here, current node does not have our desired value.
// follow the appropriate left or right child.
current = cc < 0 ? current.Left : current.Right ;
}
// once the while loop completes, current holds the result, with
// null indicating failure and non-null being the subtree containing
// the desired value as its root.
return current ;
}
I am designing a treeview which allows the user to select range of nodes by pressing SHIFT, CTRL + start node and then end node. I requirement is to select the nodes only when the range is under a treenode. (Range should not falls under two parent nodes). If user selects Node2 from two different parents i can check like if(selected_node_1->Parent == selected_node_2->Parent). But if the user selects Node_A and Node_B, how can i check whether the selected treenodes are in same level ?
(Pls note Node_A and Node_B has no parents).
Try this extension method (C#):
public static class TreeNodeExtensions {
public static int Level(this TreeNode value) {
if (Object.ReferenceEquals(null, value))
throw new ArgumentNullException("value"); // <- or return 0
int result = 0;
for (TreeNode node = value; node != null; node = node.Parent)
result += 1;
return result;
}
}
...
TreeNode node1 = ...
TreeNode node2 = ...
if (node1.Level() != node2.Level()) {
...
}
Doesn't they have parent called root?
if not you can check if both has parent == null
I have following function for searching through the Treeview:
public static TreeNode FindAllNamesInTreeView(TreeView treeView, String name, int StartNode = -1, bool Searchilds = true)
{
TreeNode newNode = new TreeNode("SRes");
newNode.Nodes.Add("Test");
// check if we have a treeview
if (treeView == null)
return null;
// iterate through the treeview's root nodes
for (int i = 0; i < treeView.Nodes.Count; i++)
{
// for each root node try to find the node with the name we want
TreeNode foundNode = FindNameInTreeView(treeView.Nodes[i], name, StartNode, Searchilds);
// if we found the node, return it
if (foundNode != null)
if (TheIndexOf(foundNode) > StartNode)
newNode.Nodes.Add( foundNode); //Error here!
}
// no node found
return newNode;
}
On executing the newNode.Add(foundNode); I have the following exception:
'A first chance exception of type 'System.ArgumentException' occurred in System.Windows.Forms.dll'
Could anybody tell me what's wrong or how I can add collect all found nodes to one here ?
You can't add the same node to two trees. Therefore, if you find one, and try to add it to newNode, you get an ArgumentException.
Instead of using a TreeNode, I would suggest returning a List<TreeNode> instead.
public void Insert(int value)
{
if (value < Data)
{
if (LeftNode == null)
{
LeftNode = new TreeNode(value);
}
else
{
LeftNode.Insert(value);
}
}
else if (value > Data)
{
if (RightNode == null)
{
RightNode = new TreeNode(value);
}
else
{
RightNode.Insert(value);
}
}
}
I wrote method to add element in BST recursively, It checks for value to add less than or greater than and add it in its proper place, but I want to know how iterative method works? I need iterative add method for my BST.
Ok, here's an iterative version of your algorithm:
public void Insert(int value)
{
TreeNode current = this;
while (current != null)
{
if(current.Data < value)
if(current.LeftNode == null)
{ current.LeftNode = new TreeNode(value); break; }
else current = current.LeftNode;
else
if(current.RightNode == null)
{ current.RightNode = new TreeNode(value); break; }
else current = current.RightNode;
}
}
You can find a implementation in Java at wikipedia, what is very similar C# http://en.wikipedia.org/wiki/Binary_search_tree
We start at root:
Node root = m_root;
while (root != null) {
then look if the value is less os greater than root.
if (data < root.getData()) {
Now we know if we need to traverse at left or right. The logic at left and right are the same. We look if the slot is empty and if it is, we put the value at that slot.
if (root.getLeft() == null) {
root.setLeft(new TreeNode(data, null, null));
return;
}
If the slot contains a value, then we set that slot as root and continue the process.
} else {
root = root.getLeft();
}
An iterative method is one that will repeat.
Iterative method implies it will be called repeatedly.
Recursion implies the method will call itself n times, where n > 0.
Searching a binary search tree is done using a method which calls itself (recursive) until it finds the end of a branch.
To do an insert, a search is executed to find the correct place to place the node.
I saw the following post order traversal algorithm in some website... it seems to be correct. I just want to verify that this algorithm works correctly — is this algorithm correct for post order traversal without recursion?
void postOrderTraversal(Tree *root)
{
node * previous = null;
node * s = null;
push(root);
while( stack is not empty )
{
s = pop();
if(s->right == null and s->left == null)
{
previous = s;
process s;
}
else
{
if(s->right == previous or s->left == previous)
{
previous = s;
process s;
}
else
{
push( s );
if(s->right) { push(s->right); }
if(s->left) { push(s->left); }
}
}
}
}
Try to write iterative versions of pre-order, in-order, and post-order binary traversal methods. You will then see the pattern or methodology of converting their corresponding recursive versions into the iterative versions.
Key point is sticking to some basic rules:
- Use node selection (e.g., currentNode = currentNode->Left before reiterating the loop, etc.) for immediate node traversal.
- Use stack to remember nodes that need to be visited or revisited later.
- If a node need to be "REvisited," detecting / keeping the state so that you can indicate whether the next node needs to be "processed" in next iteration or one of more of the child nodes should be visited before the node can be processed.
If you stick to these rules, you can esily accomplish the tasks.
Here is an example of the iterative post-order traversal. Ignore BinarySearchTree - it works for any binary trees.
public static IEnumerator<BinarySearchTreeNode<T>> GetPostOrderTraverseEnumerator(BinarySearchTreeNode<T> root)
{
if (root == null)
{
throw new ArgumentNullException("root");
}
Stack<BinarySearchTreeNode<T>> stack = new Stack<BinarySearchTreeNode<T>>();
BinarySearchTreeNode<T> currentNode = root;
// If the following flag is false, we need to visit the child nodes first
// before we process the node.
bool processNode = false;
while (true)
{
// See if we need to visit child nodes first
if (processNode != true)
{
if (currentNode.Left != null)
{
// Remember to visit the current node later
stack.Push(currentNode);
if (currentNode.Right != null)
{
// Remember to visit the right child node later
stack.Push(currentNode.Right);
}
// Visit the left child
currentNode = currentNode.Left;
continue;
}
else if (currentNode.Right != null)
{
// Remember to visit the current node later
stack.Push(currentNode);
// Visit the right child
currentNode = currentNode.Right;
continue;
}
}
// Process current node
yield return currentNode;
// See if we are done.
if (stack.Count == 0)
{
break;
}
// Get next node to visit from the stack
BinarySearchTreeNode<T> previousNode = currentNode;
currentNode = stack.Pop();
// See if the next node should be processed or not
// This can be determined by the fact that either of the current node's child nodes
// has just been processed now.
processNode = (previousNode == currentNode.Left || previousNode == currentNode.Right);
}
}
no here prev should not start with null
eg:for bst having nodes 5 2 1 3 7 6 8 0
it will not consider zero because at 1 its right is null and this time previous will also be null hence it will not consider its left child i.e. 0
write previous=any value but not null
Here is the working code
Stack s=new Stack();
while(true){
if(root!=null){
s.push(root);
root=root.left;
}
else{
if(s.top().right==NULL){
root=s.top();
s.pop();
System.out.println(root.data);
if(root==s.top().right){
System.out.println(s.top().data);
s.pop();
}
}
if(!s.empty())
root=s.top().right;
else
root=NULL;
}
}