Two trees can be called isomorphic if they have similar structure and the only difference amongst them can be is, that their child nodes may or may not be swapped. For example:
4 4
/ \ / \
2 6 and 6 2
/ \ / \ / \ / \
1 3 5 7 1 3 7 5
The following code is supposed to be correct implementation which I found in the web, but for some reason it is not working for the above trees. What I am doing wrong?
#include <iostream>
using namespace std;
class Node{
public:
Node * left;
Node * right;
int val;
Node(int v){
left = NULL;
right = NULL;
val = v;
}
};
bool isIsomorphic(Node* n1, Node *n2)
{
// Both roots are NULL, trees isomorphic by definition
if (n1 == NULL && n2 == NULL)
return true;
// Exactly one of the n1 and n2 is NULL, trees not isomorphic
if (n1 == NULL || n2 == NULL)
return false;
if (n1->val != n2->val)
return false;
// There are two possible cases for n1 and n2 to be isomorphic
// Case 1: The subtrees rooted at these nodes have NOT been "Flipped".
// Both of these subtrees have to be isomorphic, hence the &&
// Case 2: The subtrees rooted at these nodes have been "Flipped"
return
(isIsomorphic(n1->left,n2->left) && isIsomorphic(n1->right,n2->right))||
(isIsomorphic(n1->left,n2->right) && isIsomorphic(n1->right,n2->left));
}
int main()
{
Node * na_4 = new Node(4);
Node * na_2 = new Node(2);
Node * na_6 = new Node(6);
Node * na_1 = new Node(1);
Node * na_3 = new Node(3);
Node * na_5 = new Node(5);
Node * na_7 = new Node(7);
na_4->left = na_2;
na_4->right = na_6;
na_2->left = na_1;
na_2->right = na_3;
na_6->left = na_5;
na_6->right = na_7;
Node * nb_4 = new Node(4);
Node * nb_6 = new Node(6);
Node * nb_2 = new Node(2);
Node * nb_1 = new Node(1);
Node * nb_3 = new Node(3);
Node * nb_7 = new Node(7);
Node * nb_5 = new Node(5);
nb_4->left = nb_6;
nb_4->right = nb_2;
nb_6->left = nb_1;
nb_6->right = nb_3;
nb_2->left = nb_7;
nb_2->right = nb_5;
if(isIsomorphic(na_4, nb_4)){
cout << "Yes they are isomorphic" << endl;
}
else
{
cout << "No there are not isomorphic" << endl;
}
return 0;
}
It outputs that they are not isomorphic.
Those trees aren't isomorphic according to the definition you provided. A similar definition that's specific to binary trees also appears here:
Two trees are called isomorphic if one of them can be obtained from other by a series of flips, i.e. by swapping left and right children of a number of nodes. Any number of nodes at any level can have their children swapped. Two empty trees are isomorphic.
The problem is that in the one tree, 2 has children 1 and 3, but in the other tree, 2 has children 7 and 5.
By "swapping" two children, you actually need to swap their entire subtrees, not just the individual nodes and leaving all others where they are.
These two, for example, would be isomorphic:
4
/ \
2 6
/ \ / \
1 3 5 7
4
/ \
6 2
/ \ / \
7 5 1 3
Note: Some definitions of isomorphism ignore vertex labels (for more general graph isomorphism at least, in principle the same idea would apply to trees as well). Under those definitions, the trees given in the question would be isomorphic. I believe the definition given above would still apply if you ignore vertex labels. For graph isomorphism (as opposed to tree isomorphism, which takes the root into account), this would not work as general graphs have no concept of a root (trees produced by the above technique would still be graph isomorphic, but not all graphs isomorphisms can be produced using this technique).
These given trees are not isomorphic. Two trees are called isomorphic if and only if one of them can be obtained from other by a series of flips, i.e. by swapping left and right children of a number of nodes. Also, any number of nodes at any level can have their children swapped.
Related
In https://www.techiedelight.com/print-all-paths-from-root-to-leaf-nodes-binary-tree/, the code for printing root to leaf for every leaf node is provided below.
They state the algorithm is O(n), but I think it should be O(n log n) where n is the number of nodes. A standard DFS is typically O(n + E), but printing the paths seems to add a log n. Suppose h is the height of the perfect binary tree. There are n/2 nodes on the last level, hence n/2 paths that we need to print. Each path has h + 1 (let's just say it's h for mathematical simplicity) nodes. So we need end up printing h * n/2 nodes when printing all the paths. We know h = log2(n). So h * n/2 = O(n log n)?
Is their answer wrong, or is there something wrong with my analysis here?
#include <iostream>
#include <vector>
using namespace std;
// Data structure to store a binary tree node
struct Node
{
int data;
Node *left, *right;
Node(int data)
{
this->data = data;
this->left = this->right = nullptr;
}
};
// Function to check if a given node is a leaf node or not
bool isLeaf(Node* node) {
return (node->left == nullptr && node->right == nullptr);
}
// Recursive function to find paths from the root node to every leaf node
void printRootToleafPaths(Node* node, vector<int> &path)
{
// base case
if (node == nullptr) {
return;
}
// include the current node to the path
path.push_back(node->data);
// if a leaf node is found, print the path
if (isLeaf(node))
{
for (int data: path) {
cout << data << " ";
}
cout << endl;
}
// recur for the left and right subtree
printRootToleafPaths(node->left, path);
printRootToleafPaths(node->right, path);
// backtrack: remove the current node after the left, and right subtree are done
path.pop_back();
}
// The main function to print paths from the root node to every leaf node
void printRootToleafPaths(Node* node)
{
// vector to store root-to-leaf path
vector<int> path;
printRootToleafPaths(node, path);
}
int main()
{
/* Construct the following tree
1
/ \
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
Node* root = new Node(1);
root->left = new Node(2);
root->right = new Node(3);
root->left->left = new Node(4);
root->left->right = new Node(5);
root->right->left = new Node(6);
root->right->right = new Node(7);
root->right->left->left = new Node(8);
root->right->right->right = new Node(9);
// print all root-to-leaf paths
printRootToleafPaths(root);
return 0;
}
The time comlexity of finding path is O(n) where it iterates through all nodes once.
The time comlexity of "print one path" is O(log n).
To print all paths (n/2 leaf), it takes O( n log n )
Then you need to compare node traverse cost and print path cost.
I believe in most of modern OS, print cost is much greater than node traverse cost.
So the actual time complexity is O(n log n) ( for print ).
I assume the website might ignore print cost so it claims time complexity is O(n).
The complexity is O(n log n) for a balanced binary tree, but for an arbitrary binary tree, the worst case is O(n2).
Consider a tree consisting of:
n/2 nodes in a linked list on their rightChild pointers; and
At the end of that, n/2 nodes arranged into a tree with n/4 leaves.
Since the n/4 leaves are all more than n/2 nodes deep, there are more than n2/8 total nodes in all the paths, and that is O(n2)
The algorithm traverses O(n) nodes. The total prints it does is O(n lg n) for a balanced tree or O(n^2) for an arbitrary tree.
It depends on what operations have cost.
For example, storing or incrementing an n bit number or pointer is often treated as an O(1) operation. In any physical computer, if you have 2^100 nodes you'll need lg(2^100) bit pointers (or node names) which will require more time to copy than 64 or 32 bit node names. Jn a certain sense, copying a pointer should take O(lg n) time!
But we don't care. We implicitly set the price of operations, and give O notation costs in terms of those operations.
Here, it is plausible they counted printing the entire path as an O(1) operation, and counted node traversals, to get an O(n) cost. Maybe they did it even notice, no more than you noticed the max node count implied by 32 or 64 bit pointers. They failed to tell you how they are pricing things.
The same thing happens in the specification of std library algorithms; it guarantees a max number of calls of a predicate.
Like the title says, I want to count the nodes in for any given level of the tree. I already know how to make member functions for counting all the nodes of the tree, just not sure how to approach a specific level. Here's what I've tried. Any help is appreciated.
First parameter is a point to a character array inputted by the user. root is a private variable representing the "oldest" node.
int TreeType::GetNodesAtLevel(ItemType* itemArray, int level)
{
TreeNode* p = root;
if (itemArray == NULL)
return;
if (level == 0)
{
cout << p->info << " ";
return;
}
else
{
GetNodesAtLevel(itemarray->left, level); //dereference in one and not the other was just testing
GetNodesAtLevel(*itemarray->right, level); //neither seems to work
}
}
The way to do it is by using a queue (employing level order traversal - BFS). Now follow this:
Take two variables, count_level and count_queue (keeping total nodes in a queue).
for a tree like this:
A
/ \
B C
/ \ \
K L D
/
E
initially count_level = 0 and count_queue = 0. Now:
Add a node to the queue(at this point A, increment count_queue to 1).
Now when you find count_level = 0 do this -> count_level = count_queue.
Add the kid nodes while dequeuing till the count_level becomes 0. So at this point the follow step 2 and that will give you the no of nodes at level beneath what just has been processed.
I have a binary tree with nodes like this:
struct node
{
int info;
node *left = NULL;
node *right = NULL;
node();
node(int data, node* ln = 0, node* rn = 0): info(data), left(ln), right(rn) {}
};
bool addItemToTree(struct node* node, int item, bool isRoot) {
if (!node)
return false;
if (isRoot) {
node->info = item;
return true;
}
if (!node->left) {
node->left = new struct node(item);
}
else if (!node->right) {
node->right = new struct node(item);
}
else {
if (node->left->left && node->left->right && (!node->right->left || !node->right->right)) {
return addItemToTree(node->right, item, false);
}
else {
return addItemToTree(node->left, item, false);
}
}
return true;
}
int main()
{
node* root = createRoot();
for (int i = 1; i <= 13; i++) {
if (i == 1) {
addItemToTree(root, i, true);
}
else {
addItemToTree(root, i, false);
}
}
}
For some reason, my insert function (adds element to tree) stops working after 10 iterations, meaning it adds elements into an incorrect node (doesn't follow binary tree pattern). Anyone know why it breaks? Thanks.
I assume it's actually after 11 iterations, not 10.
That's because after 11 iterations your tree looks like this:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \ / \
8 9 10 11
Now you want to add 12 under 6, for that your addItemToTree, when looking at 1, needs to go to the right. But it only goes to the right if the right child has no children of its own. In this case the right child of 1 is 3, and it has children of its own, so your method will go to the left, which is wrong.
To fix it, you will need to maintain some auxiliary information about the nodes that would let you decide when to go to the left and when to the right. Some options:
Store the total number of nodes in a subtree. If the left subtree has number of children that is 1 less that some power of two, and the right child has less than that, go to the right (try to prove why that works).
Store whether a subtree has openings at the current depth. You go to the left child if either left->hasOpenings or if !left->hasOpenings && !right->hasOpenings (the latter means that the tree is full at the current depth, and needs to be extended). You set hasOpenings for a parent of a node whenever you recurse to a left child of the node.
In your addItemToTree maintain the current depth (the depth of the root being 0). Let leftmostOne be the index of the leftmost 1 in the binary representation of item. Go to the left if item & (1 << (leftmostOne - depth - 1)) == 0. E.g. when you add 9, the leftmostOne is 3. Then you will do three iterations, and make the following decisions:
At node 1, depth 0, 9 & (1 << (3 - 0 - 1)) = 0, go left
At node 2, depth 1, 9 & (1 << (3 - 1 - 1)) = 0, go left
At node 3, depth 2, 9 & (1 << (3 - 2 - 1)) = 1, go right
Which is exactly what you want.
Try to prove why this works for the general case.
I am having a binary tree
2
/ \
3 4
/ \ \
5 1 8
/ \ / \
1 6 9 2
\
4
i want to find the maximum possible triangular chord info sum of nodes ( between any two leaves and a node having both left and right child ) in the given tree.
a triangular chord will be
for triangular chord :
just imagine a line between any two leaves, go upward towards root, find a common parent (that can be parent, grandparent, grandgrandparent or even the root itself). While moving upwards, for each leaf ( for any leaf either we have to go upward only left left left .... and so OR either only right right right right .. and so) means ( left leaf will only move right upward only and right leaf will move left upward only..... So for any single leaf, we can not move in both direction while moving upwards).. Now we get a triangular shape.. in which a side may contain any no. of nodes/links possible.. NOW, if that triangular shape does not contain any extra internal branches. that triangular shape will be a triangular chord.
Do remember that every leaf node is also always a triangular chord (It is just to create the default cases if the binary tree do not have any triangular shaped chord)
now
maximum triangular chord will be that triangular chord
which have maximum total in sum of all its node info.
we are required to return that maximum total.
If we do not have triangular shaped chord..
then we have to return the leaf with maximum info.
for example
8
/ \
2 3
\
3
is a triangular chord
8
/ \
2 3
\ \
4 1
only subtree with single node 4 will be maximum triangular chord (as its sum is greater than another triangular chord with single node 1) Not the whole tree will be triangular chord
8
/ \
2 3
/ \
4 3
is a triangular chord
so the solution of the very first tree on the first line of question is
8+9+2+4 = 23
i am badly trapped in this problem.
I have a rough approach
I will recursively call leftchild as root of subtree and find the left maximum triangular chord sum
then same for rightchild as root of subtree.
add the max of leftmax and rightmax, and the add to rood node and return
in c++ mycode is :
int maxtri(node* n)
{
if(n)
{
lsum = maxtri(n->left);
rsum = maxtri(n->right);
k = maxof(lsum,rsum);
return (n->info + k);
}
}
edit : my another recursive approach
int l =0, r =0;
int maxtri(node* n)
{
if (n == NULL) return 0;
if (!(n->left) && !(n->right)) return n->info;
if ((n->left) && (n->right))
{
l = maxtri(n->left);
r = maxtri(n->right);
}
if ((n->left) && !(n->right))
{
l = l + maxtri(n->left);
}
if (!(n->left) && (n->right))
{
r = r + maxtri(n->right);
}
return (l+r+n->info);
}
i have doubt on my approach.
can anyone give another solution.??
What about this logic:
For each node traverse the left portion and right portion, if you find any branches then don't consider this node in your calculation else consider this. Moreover, for the part of calculation node should have left & right nodes or it should be leaf node.
Note: I have not tested it properly but i believe it should work.
// Node by Node traverse the tree
void addSum(Node *head, vector<int>& sum)
{
if (head == NULL)
return;
else {
int s = traverseThisNode(head);
sum.push_back(s); // Add to vector
addSum(head->left, sum);
addSum(head->right, sum);
}
}
// For each node traverse left & right
int traverseThisNode(Node *head)
{
if (head && head->left && head->right) {
Node *temp = head; // To traverse right portion of this node
int sum = head->value;
while(head->left) { // Traverse right
head = head->left;
sum = sum + head->value;
if (head->right) { // Condition to check if there is any branching
sum = 0;
break;
}
}
while(temp->right && sum != 0) { // Traverse Right now
temp = temp->right;
sum = sum + temp->value;
if (temp->left) { // Condition to check if there is any branching
sum = 0;
break;
}
}
return sum;
} else if (head && !head->left && !head->right) {
return head->value; // To add leaf node
}
return 0;
}
Now you have vector containing all the value of triangular in the tree, traverse it and
find the maximum.
int maximum()
{
// Traverse the vector "sum" & find the maximum
}
I write the pseudocode for my approach, as far as I have understood the question.
Max = min_value; //possibly 0 if no negative value is allowed for nodes.
sum = 0;
for each node in the tree
temp = node;
sum+= temp->data //collects data at the current level, the current level may be leaf too.
Until temp->left is not null, // Traversing uni-directionally to the left most deep and collecting data.
temp = temp->left
sum+=temp->data
Until temp->right is not null, // Traversing uni-directionally to the right most deep and collecting data.
temp = temp->right
sum+= temp->data
if(sum > Max)
Max = sum;
sum = 0;
print Max;
Came across this question in an interview.
Given inorder traversal of a binary tree. Print all the possible binary trees from it.
Initial thought:
If say we have only 2 elements in the array. Say 2,1.
Then two possible trees are
2
\
1
1
/
2
If 3 elements Say, 2,1,4. Then we have 5 possible trees.
2 1 4 2 4
\ / \ / \ /
1 2 4 1 4 2
\ / / \
4 2 1 1
So, basically if we have n elements, then we have n-1 branches (childs, / or ).
We can arrange these n-1 branches in any order.
For n=3, n-1 = 2. So, we have 2 branches.
We can arrange the 2 branches in these ways:
/ \ \ / /\
/ \ / \
Initial attempt:
struct node *findTree(int *A,int l,int h)
{
node *root = NULL;
if(h < l)
return NULL;
for(int i=l;i<h;i++)
{
root = newNode(A[i]);
root->left = findTree(A,l,i-1);
root->right = findTree(A,i+1,h);
printTree(root);
cout<<endl;
}
}
This problem breaks down quite nicely into subproblems. Given an inorder traversal, after choosing a root we know that everything before that is the left subtree and everthing after is the right subtree (either is possibly empty).
So to enumerate all possible trees, we just try all possible values for the root and recursively solve for the left & right subtrees (the number of such trees grows quite quickly though!)
antonakos provided code that shows how to do this, though that solution may use more memory than desirable. That could be addressed by adding more state to the recursion so it doesn't have to save lists of the answers for the left & right and combine them at the end; instead nesting these processes, and printing each tree as it is found.
I'd write one function for constructing the trees and another for printing them.
The construction of the trees goes like this:
#include <vector>
#include <iostream>
#include <boost/foreach.hpp>
struct Tree {
int value;
Tree* left;
Tree* right;
Tree(int value, Tree* left, Tree* right) :
value(value), left(left), right(right) {}
};
typedef std::vector<Tree*> Seq;
Seq all_trees(const std::vector<int>& xs, int from, int to)
{
Seq result;
if (from >= to) result.push_back(0);
else {
for (int i = from; i < to; i++) {
const Seq left = all_trees(xs, from, i);
const Seq right = all_trees(xs, i + 1, to);
BOOST_FOREACH(Tree* tl, left) {
BOOST_FOREACH(Tree* tr, right) {
result.push_back(new Tree(xs[i], tl, tr));
}
}
}
}
return result;
}
Seq all_trees(const std::vector<int>& xs)
{
return all_trees(xs, 0, (int)xs.size());
}
Observe that for root value there are multiple trees that be constructed from the values to the left and the right of the root value. All combinations of these left and right trees are included.
Writing the pretty-printer is left as an exercise (a boring one), but we can test that the function indeed constructs the expected number of trees:
int main()
{
const std::vector<int> xs(3, 0); // 3 values gives 5 trees.
const Seq result = all_trees(xs);
std::cout << "Number of trees: " << result.size() << "\n";
}