Lab Manual Tree
Lab Manual Tree
Given a Binary Tree, find the maximum(or minimum) element in it. For example, maximum in
the following Binary Tree is 9.
In Binary Search Tree, we can find maximum by traversing right pointers until we reach the
rightmost node. But in Binary Tree, we must visit every node to figure out maximum. So the idea
is to traverse the given tree and for every node return maximum of 3 values.
1. Node’s data.
2. Maximum in node’s left subtree.
3. Maximum in node’s right subtree.
Below is the implementation of above approach.
C++Java
// C++ program to find maximum and
// minimum in a Binary Tree
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
// A tree node
class Node {
public:
int data;
Node *left, *right;
/* Constructor that allocates a new
node with the given data and NULL
left and right pointers. */
Node(int data)
{
this->data = data;
this->left = NULL;
this->right = NULL;
}
};
// Driver Code
int main()
{
Node* NewRoot = NULL;
Node* root = new Node(2);
root->left = new Node(7);
root->right = new Node(5);
root->left->right = new Node(6);
root->left->right->left = new Node(1);
root->left->right->right = new Node(11);
root->right->right = new Node(9);
root->right->right->left = new Node(4);
// Function call
cout << "Maximum element is " << findMax(root) << endl;
return 0;
}
Output
Maximum element is 11
Complexity Analysis:
Given a Binary Search Tree and a node value x. Delete the node with the given value
x from the BST. If no node with value x exists, then do not make any change. Return
the root of the BST after deleting the node with value x. Do not make any update if
there's no node with value x present in the BST.
Note: The generated output will be the inorder traversal of the modified tree.
Examples :
Input:
2
/ \
1 3
x = 12
Output: 1 2 3
Explanation: In the given input there is no node with
value 12 , so the tree will remain same.
Input:
1
\
2
\
8
/ \
5 11
/ \ / \
4 7 9 12
x = 9
Output: 1 2 4 5 7 8 11 12
Explanation: In the given input tree after deleting 9
will be
1
\
2
\
8
/ \
5 11
/ \ \
4 7 12
Expected Time Complexity: O(Height of the BST).
Expected Auxiliary Space: O(Height of the BST).
Node * minValueNode(Node* node)
current = current->left;
return current;
// base case
// to be deleted
else
if (root->left == NULL)
free(root);
return temp;
free(root);
return temp;
}
// node with two children: Get the inorder successor (smallest
root->data = temp->data;
return root;
Description - The diameter of a tree (sometimes called the width) is the number of nodes on the
longest path between two end nodes. The diagram below shows two trees each with diameter
nine, the leaves that form the ends of a longest path are shaded (note that there is more than one
path in each tree of length nine, but no path longer than nine nodes).
Solution - The diameter of a tree T is the largest of the following quantities:
Pseudo Code
int lh = 0, rh = 0
int ldiameter = 0, rdiameter = 0
if(root == NULL)
{
*height = 0
return 0 /* diameter is also 0 */
}
ldiameter = diameter(root->left, &lh)
rdiameter = diameter(root->right, &rh)
Size of a tree is the number of elements present in the tree. Size of the below tree is 5.
Algorithm:
size(tree)
1. If tree is empty then return 0
2. Else
(a) Get the size of left subtree recursively i.e., call
size( tree->left-subtree)
(a) Get the size of right subtree recursively i.e., call
size( tree->right-subtree)
(c) Calculate size of the tree as following:
tree_size = size(left-subtree) + size(right-
subtree) + 1
(d) Return tree_size
C++Java
// A recursive C++ program to
// calculate the size of the tree
#include <bits/stdc++.h>
using namespace std;
return(Node);
}
/* Driver code*/
int main()
{
node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
Output:
The extra space is due to the recursion call stack and the worst case occurs when the tree is either
left skewed or right skewed.
Since this program is similar to traversal of tree, time and space complexities will be same as
Tree traversal
A height balanced binary tree is a binary tree in which the height of the left subtree and
right subtree of any node does not differ by more than 1 and both the left and right
subtree are also height balanced.
In this article, we will look into methods how to determine if given Binary trees are height-
balanced
Examples: The tree on the left is a height balanced binary tree. Whereas the tree on the
right is not a height balanced tree. Because the left subtree of the root has a height which
is 2 more than the height of the right subtree.
Get the height of left and right subtrees using dfs traversal. Return true if the difference
between heights is not more than 1 and left and right subtrees are balanced, otherwise
return false.
C++Java
/* CPP program to check if
a tree is height-balanced or not */
#include <bits/stdc++.h>
using namespace std;
// Driver code
int main()
{
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->left->left->left = new Node(8);
if (isBalanced(root))
cout << "Tree is balanced";
else
cout << "Tree is not balanced";
return 0;
}
Output
Tree is not balanced
Time Complexity: O(n^2) in case of full binary tree.
Auxiliary Space: O(n) space for call stack since using recursion
Calculating the height in the same recursion rather than calling a height() function
separately.
For each node make two recursion calls – one for left subtree and the other for the right
subtree.
Based on the heights returned from the recursion calls, decide if the subtree whose root is
the current node is height-balanced or not.
If it is balanced then return the height of that subtree. Otherwise, return -1 to denote that
the subtree is not height-balanced.
Below is the implementation of the above approach.
C++Java
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
// Driver code
int main()
{
Node* root = new Node(10);
root->left = new Node(5);
root->right = new Node(30);
root->right->left = new Node(15);
root->right->right = new Node(20);
if (isBalanced(root) > 0)
cout << "Balanced";
else
cout << "Not Balanced";
return 0;
}
Output
Balanced
Time Complexity: O(n)
Because we are only one dfs call and utilizing the height returned from that to determine
the height balance, it is performing the task in linear time.
Auxiliary Space: O(n)
The diameter of a tree (sometimes called the width) is the number of nodes on the longest path
between two end nodes. The diagram below shows two trees each with diameter nine, the leaves
that form the ends of a longest path are shaded (note that there is more than one path in each tree
of length nine, but no path longer than nine nodes).
Where,
lDiameter = Diameter of left subtree
rDiameter = Diameter of right subtree
lHeight = Height of left subtree
rHeight = Height of right subtree
Implementation :
C++Java
// C++ program to calculate Diameter of a Binary Tree
#include <bits/stdc++.h>
using namespace std;
// Driver Code
int main()
{
return 0;
}’
Output:
The above implementation can be optimized by calculating the height in the same
recursion rather than calling a height() separately.
C++JavaPython3C#Javascript
// Recursive optimized C++ program to find the diameter of a
// Binary Tree
#include <bits/stdc++.h>
using namespace std;
if (root == NULL) {
*height = 0;
return 0; // diameter is also 0
}
// Driver Code
int main()
{
int height = 0;
// Function Call
cout << "Diameter of the given binary tree is "
<< diameterOpt(root, &height);
return 0;
}
Output
A binary search tree (BST) is a node based binary tree data structure which has the
following properties.
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the
node's key.
Both the left and right subtrees must also be binary search trees.
From the above properties it naturally follows that:
C++Java
int isBST(struct node* node)
{
if (node == NULL)
return 1;
This approach is wrong as this will return true for below binary tree (and below
tree is not a BST because 4 is in left subtree of 3)
C++Java
/* Returns true if a binary tree is a binary search tree */
int isBST(struct node* node)
{
if (node == NULL)
return 1;
It is assumed that you have helper functions minValue() and maxValue() that return the
min or max int value from a non-empty tree
Note: This method is not applicable if there are duplicate elements with value INT_MIN
or INT_MAX.
C++Java
#include<bits/stdc++.h>
/* Driver code*/
int main()
{
node *root = new node(4);
root->left = new node(2);
root->right = new node(5);
root->left->left = new node(1);
root->left->right = new node(3);
if(isBST(root))
cout<<"Is BST";
else
cout<<"Not a BST";
return 0;
}
Output:
IS BST
Time Complexity: O(n)
Auxiliary Space: O(1) if Function Call Stack size is not considered, otherwise O(n)
Simplified Method 3
We can simplify method 2 using NULL pointers instead of INT_MIN and INT_MAX
values.
C++Java
// C++ program to check if a given tree is BST.
#include <bits/stdc++.h>
using namespace std;
if (isBST(root,NULL,NULL))
cout << "Is BST";
else
cout << "Not a BST";
return 0;
}
Output:
Not a BST
METHOD 4(Using In-Order Traversal)
Thanks to LJW489 for suggesting this method.
1) Do In-Order Traversal of the given tree and store the result in a temp array.
2) This method assumes that there are no duplicate values in the tree
3) Check if the temp array is sorted in ascending order, if it is, then the tree is BST.
Time Complexity: O(n)
We can avoid the use of a Auxiliary Array. While doing In-Order traversal, we can keep
track of previously visited node. If the value of the currently visited node is less than the
previous value, then tree is not BST. Thanks to ygos for this space optimization.
C++Java
bool isBST(node* root)
{
static node *prev = NULL;
prev = root;
return isBST(root->right);
}
return true;
}
The use of a static variable can also be avoided by using a reference to the prev node as
a parameter.
C++Java
// C++ program to check if a given tree is BST.
#include <bits/stdc++.h>
using namespace std;
prev = root;
return true;
}
if (isBST(root))
cout << "Is BST";
else
cout << "Not a BST";
return 0;
}
Output:
Not a BST
Given a Binary Tree and the value of two nodes n1 and n2. The task is to find the lowest
common ancestor of the nodes n1 and n2 in the given Binary Tree.
The LCA or Lowest Common Ancestor of any two nodes N1 and N2 is defined as the
common ancestor of both the nodes which is closest to them. That is the distance of the
common ancestor from the nodes N1 and N2 should be least possible.
Below image represents a tree and LCA of different pair of nodes (N1, N2) in it:
Finding LCA
Method 1: The simplest method of finding LCA of two nodes in a Binary Tree is to observe that
the LCA of the given nodes will be the last common node in the paths from the root node to the
given nodes.
Algorithm:
1. Find the path from the root node to node n1 and store it in a vector or array.
2. Find the path from the root node to node n2 and store it in another vector or array.
3. Traverse both paths untill the values in arrays are same. Return the common element just
before the mismatch.
Implementation:
C++Java
// C++ Program for Lowest Common Ancestor
// in a Binary Tree
#include <iostream>
#include <vector>
return false;
}
// Driver Code
int main()
{
// Let us create the Binary Tree
// as shown in the above diagram
Node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
return 0;
}
Output:
LCA(4, 5) = 2
LCA(4, 6) = 1
LCA(3, 4) = 1
LCA(2, 4) = 2
Analysis: The time complexity of the above solution is O(N) where N is the number of nodes in
the given Tree and the above solution also takes O(N) extra space.
Method 2: The method 1 finds LCA in O(N) time but requires three tree traversals plus extra
spaces for path arrays. If we assume that the keys are present in Binary Tree, we can find LCA
using single traversal of Binary Tree and without extra storage for path arrays.
The idea is to traverse the tree starting from the root node. If any of the given keys (n1 and n2)
matches with root, then root is LCA (assuming that both keys are present). If root doesn't match
with any of the keys, we recur for left and right subtrees. The node which has one key present in
its left subtree and the other key present in the right subtree is the LCA. If both keys lie in left
subtree, then left subtree has LCA also, otherwise, LCA lies in the right subtree.
C++Java
// C++ Program to find LCA of n1 and n2 using
// one traversal of Binary Tree
#include <iostream>
// Driver Code
int main()
{
// Let us create binary tree given in the above example
Node* root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
return 0;
}
Output:
Description - Mirror of a Binary Tree T is another Binary Tree M(T) with left and right children
of all non-leaf nodes interchanged. Trees in the below figure are mirror of each other.
Solution - The idea is to recursively call for left and right subtrees of a given node. On each
recursive call swap the pointers of the children nodes.
Pseudo Code
the Problem: Given a Binary Tree. The task is to print the nodes of the binary tree when viewed
from different sides. That is, the left view of the binary tree will contain only those nodes that
can be seen when the Binary tree is viewed from the left.
Example:
Left View: A simple solution is to notice that the nodes appearing in the left view of the
binary tree are the first nodes at every level. So, the idea is to do a level order traversal of
the binary tree using a marker to identify levels and print the first node at every level.
Below is the complete function to print left view:
CPP
// Function to print the left view of the binary tree
void leftViewUtil(Node root)
{
// Declare a queue for Level order Traversal
queue<Node*> q;
if (root == NULL)
return;
// Push root
q.push(root);
// Delimiter
q.push(NULL);
while (!q.empty()) {
Node* temp = q.front();
if (temp) {
temp = q.front();
}
// Push delimiter
// for the next level
q.push(NULL);
}
Right View: Printing Right View of the Binary Tree is similar to the above approach of
printing the Left view of the tree. The idea is to print the last node present at every level.
So, perform a level order traversal using a delimeter to identify levels and print the last
node present at every level.
Top View: Top view of a binary tree is the set of nodes visible when the tree is viewed
from the top. A node x is there in output if x is the topmost node at its horizontal
distance. Horizontal distance of left child of a node x is equal to the horizontal distance of
x minus 1, and that of right child is the horizontal distance of x plus 1. So, the idea is to
do a level order traversal of the tree and calculate the horizontal distance of every node
from the root node and print those nodes which are the first nodes of a particular
horizontal distance. Hashing can be used to keep a check on whether any node with a
particular horizontal distance is encountered yet or not. Below is the function
implementing the above approach:
CPP
// Structure of binary tree
// Binary Tree node is modified to contain
// an extra parameter hd, which is the
// horizontal distance of the node from root node.
struct Node
{
Node * left;
Node* right;
int hd;
int data;
};
queue<Node*>q;
map<int,int> m;
int hd=0;
root->hd = hd;
q.pop();
root=q.front();
}
Bottom View: The Bottom View of a binary tree can be printed using the similar
approach as that of printing the Top View. A node x is there in output if x is the bottom
most instead of the top most node at its horizontal distance. The process of printing the
bottom view is almost the same as that of top view with a little modification that while
storing the node's data along with a particular horizontal distance in the map, keep
updating the node's data in the map for a particular horizontal distance so that the map
contains the last node appearing with a particular horizontal distance instead of first.
Construct Binary Tree from Inorder and Preorder
Inorder sequence: D B E A F C
Preorder sequence: A B D E C F
subtree and elements on right in the right subtree. So we know the below structure now.
A
/ \
/ \
D B E F C
We recursively follow the above steps and get the following tree.
A
/ \
/ \
B C
/ \ /
/ \ /
D E F
Algorithm:
1. Pick an element from Preorder. Increment a Preorder Index Variable (preIndex in below
code) to pick the next element in the next recursive call.
2. Create a new tree node tNode with the data as the picked element.
3. Find the picked element’s index in Inorder. Let the index be inIndex.
4. Call buildTree for elements before inIndex and make the built tree as a left subtree of
tNode.
5. Call buildTree for elements after inIndex and make the built tree as a right subtree of
tNode.
6. return tNode.
We store indexes of inorder traversal in a hash table. So that search can be done O(1) time.
C++Java
/* C++ program to construct tree using inorder
and preorder traversals */
#include <bits/stdc++.h>
using namespace std;
return tNode;
}
Output