compare nodes of a binary tree - c

If I have two binary trees, how would I check if the elements in all the nodes are equal.
Any ideas on how to solve this problem?

You would do a parallel tree traversal - choose your order (pre-order, post-order, in-order). If at any time the values stored in the current nodes differ, so do the two trees. If one left node is null and the other isn't, the trees are different; ditto for right nodes.

Does node order matters? I'm assuming for this answer that the two following trees :
1 1
/ \ / \
3 2 2 3
are not equal, because node position and order is taken into account for the comparison.
A few hints
Do you agree that two empty trees are equal?
Do you agree that two trees that only have a root node, with identical node values, are equal?
Can't you generalize this approach?
Being a bit more precise
Consider this generic tree:
rootnode(value=V)
/ \
/ \
-------- -------
| left | | right |
| subtree| |subtree|
-------- -------
rootnode is a single node. The two children are more generic, and represent binary trees. The children can either be empty, or a single node, or a fully-grown binary tree.
Do you agree that this representation is generic enough to represent any kind of non-empty binary tree? Are you able to decompose, say, this simple tree into my representation?
If you understand this concept, then this decomposition can help you to solve the problem. If you do understand the concept, but can't go any further with the algorithm, please comment here and I'll be a bit more specific :)

you could use something like Tree Traversal to check each value.

If the trees are binary search trees, so that a pre-order walk will produce a reliable, repeatable ordering of items, the existing answers will work. If they're arbitrary binary trees, you have a much more interesting problem, and should look into hash tables.

My solution would be to flatten the two trees into 2 arrays (using level order), and then iterate through each item and compare. You know both arrays are the same order. You can do simple pre-checks such as if the array sizes differ then the two trees aren't the same.
Level Order is fairly easy to implement, the Wikipedia article on tree traversal basically gives you everything you need, including code. If efficiency is being asked for in the question, then a non-recursive solution is best, and done using a FIFO list (a Queue in C# parlance - I'm not a C programmer).

Let the two tree pass through same tree traversal logic and match the outputs. If even a single node data does not match the trees dont match.
Or you could just create a simple tree traversal logic and compare the node values at each recursion.

You can use pointers and recursion to check if node is equal, then check subtrees. The code can be writen as following in Java language.
public boolean sameTree(Node root1, Node root2){
//base case :both are empty
if(root1==null && root2==null )
return true;
if(root1.equals(root2)) {
//subtrees
boolean left=sameTree(root1.left,root2.left);
boolean right=sameTree(root1.right,root2.right);
return (left && right);
}//end if
else{
return false;
}//end else
}//end sameTree()

Writing a C code as a tag mentions in the question.
int is_same(node* T1,node* T2)
{
if(!T1 && !T2)
return 1;
if(!T1 || !T2)
return 0;
if(T1->data == T2->data)
{
int left = is_same(T1->left,T2->left);
int right = is_same(T1->right,T2->right);
return (left && right);
}
else
return 0;
}
Takes care of structure as well as values.

One line code is enough to check if two binary tree node are equal (same value and same structure) or not.
bool isEqual(BinaryTreeNode *a, BinaryTreeNode *b)
{
return (a && b) ? (a->m_nValue==b->m_nValue && isEqual(a->m_pLeft,b->m_pLeft) && isEqual(a->m_pRight,b->m_pRight)) : (a == b);
}

If your values are numerical int, in a known range, you can use an array, (let's say max value n). Traverse through the 1st tree using whatever method you want, adding the data into a said array, in an appropriate index (using the node data as index). Then, traverse through the second tree and check for every node in it, if array[node.data] is not null. If not - trees are identical.
**assuming for each tree all nodes are unique

Related

How can I construct a strict binary tree when the only information given is post order traversal?

Previously I asked how to get the pre-order of a tree when I am only given post-order traversal. However, now I'm curious as to how one would build a strict binary tree (strict binary tree meaning a node either has two children or no children) when only given post order traversal.
Some example data I am dealing with :
7 8 2 // 8,2 are dimensions stored in the node, likewise for other nodes)
6 4 8
3 1 5
A
B
I know what the tree is supposed to look like:
B
/ \
7 A
/ \
6 3
But I am lost on how to write a function that would actually build this tree (and store in the information in the nodes) from the information given (post order traveral.) How can I do this?
Creating a full binary tree from the postorder is like creating a syntax tree from Reverse Polish Notation with only binary operators. The branches are the operators, the leaves are the values. (You must be able to tell which is which. In your axample, brenches are letters, leaves are numbers.)
You can process the data as it comes. If it is a leaf, create a node and push it on the stack. It is is a branch, create a node, pop its right and left branches off the stack and push the new node. If the received data is valid, you should have a single node on the stack. That's the root of your tree.
So, in pseudo-ish C code:
Node *head = NULL;
while (!stream_empty()) {
int data = stream_get();
if (is_leaf(data)) {
if (nstack == MAX) fatal("Stack overflow!");
stack_push(make_node(data));
} else {
if (stack_size < 2) fatal("Stack underflow!");
Node *node = make_node(data);
node->right = stack_pop();
node->left = stack_pop();
stack_push(node);
}
}
if (nstack != 1) fatal("Ill-formed full binary tree!");
head = stack[0];
Stack overflow occurs when the tree is deeper than the stack size. Stack underflow or leftover nodes at the end occur when the input data is ill-formed.
Here's a full working example on ideone.
[Note: I've completely rewritten my answer, because the OP has specified new requirements. I had also based my original answer of a answer I gave to OP's previous question. I think that the present approach is more elegant. Whatever that means. :)]

Need some explanation about trees in C

Leaf *findLeaf(Leaf *R,int data)
{
if(R->data >= data )
{
if(R->left == NULL) return R;
else return findLeaf(R->left,data);
}
else
{
if(R->right == NULL) return R;
else return findLeaf(R->right,data);
}
}
void traverse(Leaf *R)
{
if(R==root){printf("ROOT is %d\n",R->data);}
if(R->left != NULL)
{
printf("Left data %d\n",R->left->data);
traverse(R->left);
}
if(R->right != NULL)
{
printf("Right data %d\n",R->right->data);
traverse(R->right);
}
}
These code snippets works fine but i wonder how they works?
I need a brief explanation about recursion.I am thankful for your helps.
A Leaf struct will look something like this:
typedef struct struct_t {
int data;
Leaf * left; //These allow structs to be chained together where each node
Leaf * right; //has two pointers to two more nodes, causing exponential
} Leaf; //growth.
The function takes a pointer to a Leaf we call R and some data to search against, it returns a pointer to a Leaf
Leaf *findLeaf(Leaf *R,int data){
This piece of code decides whether we should go left or right, the tree is known to be ordered because the insert function follows this same rule for going left and right.
if(R->data >= data ){
This is an edge case of the recursive nature of the function, if we have reached the last node in a tree, called the Leaf, return that Leaf.
An edge case of a recursive function has the task of ending the recursion and returning a result. Without this, the function would not finish.
if(R->left == NULL) return R;
This is how we walk through the tree, Here, we are traversing down the left side because the data was larger. (Larger data is always inserted on at the left to stay ordered.)
What is happening is that now we call findLeaf() with R->left, but imagine if we get to this point again in this next call.
It will become R->left->left in reference to the first call. If the data is smaller than the current node we are operating on we would go right instead.
else return findLeaf(R->left,data);
Now we are at the case where the data was smaller than the current Node, so we are going right.
} else {
This is exactly the same as with the left.
if(R->right == NULL) return R;
else return findLeaf(R->right,data);
}
}
In the end, the return of the function can be conceptualized as something like R->right->right->left->NULL.
Lets take this tree and operate on it with findLeaf();
findLeaf(Leaf * root, 4) //In this example, root is already pointing to (8)
We start at the root, at the top of the tree, which contains 8.
First we check R->data >= data where we know R->data is (8) and data is (4). Since we know data is smaller than R->data(Current node), we enter the if statement.
Here we operate on the left Leaf, checking if it is NULL. It isn't and so we skip to the else.
Now we return findLeaf(R->left, data);, but to return it, we must solve it first. This causes us to enter a second iteration where we compare (3) to (4) and try again.
Going through the entire process again, we will compare (6) to (4) and then finally find our node when we comepare (4) to (4). Now we will backtrack through the function and return a chain like this:
R(8)->(3)->(6)->(4)
Edit: Also, coincidentally, I wrote a blog post about traversing a linked list to explain the nature of a Binary Search Tree here.
Each Leaf contains three values:
data - an integer
left and right, both pointers to another leaf.
left, right or both, might be NULL, meaning there isn't another leaf in that direction.
So that's a tree. There's one Leaf at the root, and you can follow the trail of left or right pointers until you reach a NULL.
The key to recursion is that if you follow the path by one Leaf, the remaining problem is exactly the same (but "one smaller") as the problem you had when you were at the root. So you can call the same function to solve the problem. Eventually the routine will be at a Leaf with NULL as its pointer, and you've solved the problem.
It's probably easiest to understand a list before you understand a tree. So instead of a Leaf with two pointers, left and right, you have a Node with just one pointer, next. To follow the list to its end, recursively:
Node findEnd(Node node) {
if(node->next == NULL) {
return node; // Solved!!
} else {
return findEnd(node->next);
}
}
What's different about your findLeaf? Well, it uses the data parameter to decide whether to follow the left or right pointer, but otherwise it's exactly the same.
You should be able to make sense of traverse() with this knowledge. It uses the same principle of recursion to visit every Leaf in the structure.
Recursion is a function that breaks a problem down into 2 variants:
one step of solving the problem, and calling itself with the remainder of the problem
the last step of solving the problem
Recursion is simply a different way of looping through code.
Recursive algorithms generally work hand in hand with some form of data structure - in your case the tree. You need to imagine the recursion - very high level - as "reapply the same logic on a subset of the problem".
In your case the subset of the problem is either the branch of the three on the right or the branch of the three on the left.
So, let's look at the traverse algorithm:
It takes the leaf you pass to the method and - if it's the ROOT leaf states it
Then, if there is a "left" sub-leaf it displays the data attached to it and restarts the algorithm (the recursion) which means... on the left node
If the left node is the ROOT, state it (no chance after the first recursion since the ROOT is at the top)
Then , if there is a "left" sub-leaf to our left node, display it and restart the algorithm on this left, left
When reaching the bottom left, i.e. when there is no left leaf left (following? :) ) then it does the same on the first right leaf. If there is neither a left leaf nor a right leaf, which means we are at the real leaf that does not have sub-leafs, the recursive call ends, which means that the algorithm starts again from the place it was before recursing and with all the variables at the state they were in then.
After first recursion termination, you will move from the bottom left leaf up one leaf, and go down on the right leaf if there is one and start again printing and moving on the left.
All in all - the ending result is that you walk through your whole tree in a left first way.
Tell me if it's not crystal clear and try to apply the same pattern on the findLeaf recursive algorithm.
A little comment about recursion and then a little comment about searching on a tree:
let's suppose you want to calculate n!. You can do (pseudocode)
fac 0 = 1
fac (n+1) = (n+1) * fac n
So recursion is solving a problem by manipulating the result of solving the same problem with a smaller data. See http://en.wikipedia.org/wiki/Recursion.
So now, let's suppose we have a data structure tree
T = (L, e, R)
with L the left subtree, e is the root and R is the right subtree... So let's say you want to find the value v in that tree, you would do
find v LEAF = false // you cant find any value in an empty tree, base case
find v (L, e, R) =
if v == e
then something(e)
else
if v < e
find v L (here we have recursion, we say 'go and search for v in the left subtree)
else
find v R (here we have recursion, we say 'go and search for v in the right subtree)
end
end

Printing in ascending order (sorting) from AVL trees

I need to define a main function that reads integers and prints them back in ascending order.
For example, if the input contains
12
4
19
6
the program should output
4
6
12
19
I need to use trees to do this however. I'm given the use of two functions insertavl, and deleteavlat my disposal. Their defintions are like so... http://ideone.com/8dwlU basically when deleteavl is called it deletes the node, and rebalances the tree accordingly
... If interested thier structures are in: http://ideone.com/QjlGe.
I've gotten this so far:
int main (void) {
int number;
struct node *t = NULL;
while (1 == scanf("%d",&number)) {
t = insertavl(t, number);
}
while (t != NULL){
printf("%d\n",t->data);
t = deleteavl(t, t->data);
}
}
But this doesn't print them in ascending order. Any suggestions would be helpful? thanks in advance!
Hint: in-order traversal on a BST is iterating the elements in ascending order.
Since an AVL Tree is a specific implementation of a BST, it also applies here.
EDIT: Explanation - why is this property of in-order traversal on a BST correct?
In in-order trvaersal, you access [print] each node after you accessed all the nodes in the left subtree. Since in a BST the root is bigger then all the nodes in the left subtree, it is what we wanted.
Also, in in-order traversal, you access each node before accessing all elements in the right sub-tree, and again, since it is a BST - this is exactly what we want.
(*)Note: This is not a formal proof, just an intuitive explanation why it is true.

number of different binary trees that can be formed?

binary tree, where each node has at most two child nodes, child nodes may contain references to their parents.
we do not differentiate the nodes and all nodes are considered identical. How can we find the number of different binary trees that can be formed with N identical nodes.
eg: if 3 nodes then 5 diff trees
if 7 nodes then 429 trees
Now, if you really want to understand this, instead of just getting (or experimenting to find) the answer, you can check out "The Art of Computer Programming", Volume 4, Fascicle 4: Generating all trees.
recursion is your friend!
pseudo-code:
numOfTrees(n):
return trees(n).size();
trees(n):
if (n==1)
return new list of single node;
big_trees = new empty list;
for (small_tree : trees(n-1))
for (big_tree : addSingleNode(tree))
big_trees.insert(big_tree);
return big_trees;
addSingleNode(tree):
trees = new empty list;
for (leaf : getLeaves(tree)) {
trees.insert(tree.clone().addLeftChild(leaf, node));
trees.insert(tree.clone().addRightChild(leaf, node));
}
return trees;
getLeaves() is implementation dependant, if you have a linked list with all leaves, then it will be quick, otherwise you might have to traverse the tree checking for leaves (which is O(n) in_order).
not very memory efficient, but it solves the problem by simple recursion, where at every stage i take the trees and go over all the leaves and add my new node in every possible way.
(2n)!/[(n+1)!*n!]
have a look at:
http://www.theory.csc.uvic.ca/~cos/inf/tree/BinaryTrees.html

A recursive method to find depth of a any(not necessarily complete) Binary tree

I am trying to compute the depth of any(not necessarily complete) BST in O(log n) time recursively.
This is the algorithm I came up with:
//max() - returns the max of two numbers
int depth(root)
{
if(root->left==NULL && root->right==NULL) //leaf
return 0;
else if(root->left!=NULL && root->right==NULL) //with right leaf
return( max(depth(root->left),0)+1);
else if(root->left==NULL && root->right!=NULL) //with left leaf
return( max(0,depth(root->right)+1);
else if(root->left->left==NULL && root->left->right==NULL && root->right->left==NULL&&root->right->right==NULL) // this a parent of two leaves
return 1;
else// for the condition that this a parent of two sub roots
return( max(depth(root->right),depth(root->left))+1);
}
Is this algorithm fine for calculating depth in O(log n) time?
Is there a better way?
That's O(n) time since you may traverse every node doing that. You can do a search on a binary search tree in O(log n) but you can't find the depth of a binary tree in anything less than O(n) unless you cache the depths as you build it or do something similar.
There are two special cases you may want to be aware of.
A perfect binary tree can have its depth determined in O(log n). This means every leaf is at the same level.
Complete and balanced binary tree can have its depth approximated in O(log n) or in O(1) if the number of nodes is known. This will be approximate however (+/-1 usually).
The only way you'll get O(log(n)) runtime is if you only examine one path, and the only way you will be able to get away with examining one path is if you know that the tree has uniform height, and this only is the case with full binary trees, which your question specifically stated is not the case.
Therefore, there is no O(log(n)) algorithm that will determine the depth of a given binary tree.
You can only find the deepest node of an unknown, unbalanced tree by looking at every leaf node, which requires traversing the lot as you are doing - O(n).
As for a "better" way, you can't make it a lesser Order, but you don't need quite such complex code to achieve your result. Here is marginally less efficient implementation (because it recurses one level deeper) which is much more readable and more robust (if you pass in a NULL root pointer it won't go pop) approach:
int depth(root)
{
if (root == NULL)
return(0);
return(1 + max(depth(root->left), depth(root->right)));
}
A problem in C is that the function stack is not dynamicaly allocated on the heap, so at one point we will run out of space. Especially when each recursive call spawns two functions. In other words if your tree is somewhat balanced you will end up with log(N)^2 function calls. If you instead iterate over the left branches and recurse on the right ones, then the stack will not grow as fast.
int
depth(struct bt *root, int dl)
{
int dr, dmr;
for(dmr=dr=dl; root != NULL; dl++){
if((dr = depth(root->right, dl+1)) > dmr)
dmr = dr;
root = root->left;
}
return(dl > dmr ? dl : dmr);
}
This is the way I.E. Quick Sort is implemented in many operating systems:
http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/qsort.c?rev=1.10;content-type=text%2Fx-cvsweb-markup
int maxDepth(BST *root)
{
int ldepth=0,rdepth=0,maxdepth=0;
if(root==NULL)
return(0);
ldepth=maxDepth(root->left);
rdepth=maxDepth(root->right);
maxdepth=MAX(ldepth,rdepth);
return(maxdepth+1);
}
int TreeDepthRec(Tree *pt){
if(!*pt)
return 0;
int a = TreeDepthRec(&(*pt)->left);
int b = TreeDepthRec(&(*pt)->right);
return (a>b)? 1+a : 1+b;
}
I think comparing two integer variables takes less time than calling a function.

Resources