Binary Trees (Part 1)
Binary Trees (Part 1)
Binary Trees (Part 1)
org/a-program-to-check-if-a-binary-tree-is-bst-or-not/
https://www.geeksforgeeks.org/kth-largest-element-in-bst-when-modification-to-bst-is-not-all
https://www.techiedelight.com/determine-given-binary-tree-is-a-bst-or-not/
https://www.techiedelight.com/find-lowest-common-ancestor-lca-two-nodes-binary-tree/
https://www.techiedelight.com/calculate-height-binary-tree-iterative-recursive/
Q) Terminologies
1) Root Node :-
First or topmost node of a tree.
This node doesn’t have any parent node.
2) Sibling Node
Nodes (x1,x2,..) which appear from the same parent x are called sibling nodes.
2) Height of a Node N
Number of edges from node ‘N to the deepest leaf of it’s subtree
Height of each leaf = 0.
1) A binary tree is unlabeled if its nodes are not assigned any label
Q) Labelled Binary Tree
Q) Table 1
Max and Min no. of Nodes in some standard BT’s
When ht. h of those BT’s is provided.
Q) Table 2
Max and Min height of some standard BT’s
When no. of nodes n of those BT’s is provided.
Max ht (h m a x ) Min ht (h m i n )
(for given no. of nodes n) (for given no. of nodes n)
Binary Tree h m a x = [log 2 (n+1)] - 1 hmin = n - 1
Full Binary Tree h m a x = [log 2 (n+1)] - 1 h m i n = (n – 1)/2
Almost Complete BT h m a x = [log 2 (n+1)] - 1 h m i n = log 2 n
Q) Tree Traversals
Q) Basic Problems
Q) Find size of binary tree
Procedure:-
1) If Node x is NULL then return 0.
if (x == NULL) return 0;
int leaf_count1(Node* x)
{
if (x == nullptr)
return 0;
if ( (x->left == NULL) && (x->right == NULL) )
return 1;
return leaf_count1(x->left) + leaf_count1(x->right);
}
https://www.techiedelight.com/determine-given-binary-tree-is-a-bst-or-not/
Actual Logic :-
1) So, the condition we need to check at each node is:
If the node is the left child of its parent,
it must be smaller than (or equal to) the parent,
and it must pass down the value from its parent to its right subtree to make sure none of th
than the parent.
Ex1) Code
bool isBST(Node* x,int min_key, int max_key)
{
if(x == NULL)
return true;
// If the range of current node's data (i.e x->data)doesnt lie b/w [min_key, max_key]
// Then return false.
if( (x->data < min_key) || (x->data > max_key) )
return false;
return isBST(x->left, min_key, x->data) &&
isBST(x->right, x->data, max_key);
}
// Function to determine whether a given binary tree is a BST
void isBST(Node* root)
{
if( isBST(root, INT_MIN, INT_MAX) )
{
printf("The tree is a BST.");
}
else
{
printf("The tree is not a BST!");
}
}
2) For 2 :-
Range = [min_key, max_key] = [-inf, 4]
i.e xleft requires upper Bound
Upper Bound = x data
3) For 6 :-
Range = [min_key, max_key] = [4, inf]
i.e xright requires lower Bound
Lower Bound = x data
https://www.techiedelight.com/find-diagonal-sum-given-binary-tree/
// Perform preorder/postorder traversal (i.e perform DFS)
// And in the map m (Store the sum of all nodes) present in each and every left diags.
// In this case we are performing preorder traversal.
// We may also do postorder traversal.
void generateLeftDiagonalSum(Node* root, int diagonal, auto &m)
{
// Base Case (Empty Tree)
if(root == nullptr)
return;
m[diagonal] += root->data;
// recur for the left subtree by increasing diagonal by 1
generateDiagonalSum(root->left, diagonal+1, m);
// recur for the left subtree with the same diagonal.
generateDiagonalSum(root->right, diagonal, m);
}
//
void printLeftDiagonalSum(Node* root)
{
unordered_map<int, int> m;
// traverse the tree in a preorder fashion and fill the map
generateDiagonalSum(root, 0, m);
// traverse the map and print the diagonal sum
for (int i = 0; i < m.size(); i++)
{
printf("\nDiagonal %d Sum = %d ",i,m[i]);
}
Output :-
Diagonal 0 Sum = 10
Diagonal 1 Sum = 15
Diagonal 2 Sum = 11
Ex1) Code
// Convert the given BT to it's mirror image.
// Do a DFS Traversal (i.e postorder/preorder traversal).
void convertToMirror(Node* root)
{
// If Tree is empty (Base Case)
if(root == nullptr)
return;
// convert left subtree
convertToMirror(root->left);
// convert right subtree
convertToMirror(root->right);
// swap left subtree with right subtree
swap(root->left, root->right);
3) Interesting fact :-
Inverting a Binary Tree Converting a BT to it’s mirror image.
https://www.techiedelight.com/delete-given-binary-tree-iterative-recursive/
Q) Deleting a Binary Tree (Iterative and Recursive).
Recursive Soln.
2) Note :-
We cannot traverse the BT in a inorder or preorder fashion.
Bcoz we cannot delete a parent before deleting it’s children.
// Delete left,right subtree first (Postorder traversal)
deleteBinaryTree1(root->left);
deleteBinaryTree1(root->right);
// Delete the current node after deleting its left and right subtree
delete root;
// Set root to null before returning.
root = nullptr;
}
Iterative Soln.
3) It is important to delete the front node ONLY after enqueuing its children
void deleteBinaryTree2(Node* &root)
{
if(root == nullptr)
return;
queue<Node*> q;
q.push(root);
Node* x = nullptr;
while(!q.empty())
{
// Delete each node in the queue q one by one after pushing their
// non-empty left and right child to the queue q.
x = q.front();
q.pop();
if(x->left != nullptr)
q.push(x->left);
if(x->right != nullptr)
q.push(x->right);
// It is important to delete the front node ONLY after enqueuing its children
delete x;
}
// set root as null before returning
root = nullptr;
Q) LCA of 2 nodes in a BT
1) Suppose T = Rooted BT
n1 , n2 = Any 2 nodes in the BT.
3) For eg.
Ancestors of (6,12) = 10,15
LCA(6, 12) = 15.
Bcoz among 10, 15 15 is farthest from the root of the Tree.
https://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/
Ex1) Solution 1
https://www.geeksforgeeks.org/lowest-common-ancestor-in-a-binary-search-tree/
1) Calculating LCA for BST is even more easy than the previous one.
5) The above procedure assumes that the Nodes n1, n2 are already present in the BST.
Ex1) Recursive Implementation of the Above Logic.
Ex2) Iterative implementation of the above logic.
https://www.geeksforgeeks.org/minimum-swap-required-convert-binary-tree-binary-search-tree/
3) So number of swaps needed to convert BT to BST = number of swaps needed to convert arr to
arr = Inorder traversal of BT.
sorted_arr = Inorder traversal of BST.
4)
1) Unlike linked lists, 1D arrays, and other linear data structures , which are traversed in linear o
Trees can be traversed in multiple ways in depth–first order (preorder , inorder , and postor
or breadth–first order (level order traversal ).
2) Beyond these basic traversals,
various more complex or hybrid schemes are possible,
such as depth-limited searches like iterative deepening depth–first search.
4) The traversal can be done iteratively where the deferred nodes are stored in the stack ,
or it can be done by recursion , where the deferred nodes are stored implicitly in the call st
// Recursive InOrder Traversal 😎😎 // Recursive PreOrder Travers
void inorder1(Node* root) void preorder1(Node* root)
{ {
if(root == nullptr) if(root == nullptr)
return; return;
inorder1(root->left); cout<<root->data<<",";
cout<<root->data<<","; preorder1(root->left);
inorder1(root->right); preorder1(root->right);
} }
Output :- Output :-
Inorder Traversal :- 4,2,1,7,5,8,3,6, Preorder Traversal :- 1,2,4,3,
// Recursive PostOrder Traver
void postorder1(Node* root)
{
if(root == nullptr)
return;
postorder1(root->left);
postorder1(root->right);
cout<<root->data<<",";
}
Output :-
Postorder Traversal :- 4,2,7,8
Ex1) Code
// Function to print level order traversal of a given binary tree
void print_level_order(Node* root)
{
if(root == NULL)
return;
// create an empty queue and enqueue the root node
queue<Node*> q;
q.push(root);
// Loop till the Queue is empty.
while(!q.empty())
{
Node* x = q.front();
cout<<x->data<<",";
q.pop();
if(x->left != NULL){
q.push(x->left);
}
if(x->right != NULL){
q.push(x->right);
}
}
}
Ex1) Code
// Find ht of the given Node x. // Print the nodes at the sp
int height(Node* x) // From Left to Right (Defaul
{ void print_given_level(Node*
if(x == NULL) {
return 0; if(root == NULL)
return;
int lheight = height(x->left);
int rheight = height(x->right); if(level == 1)
cout<<root->data<<","
return max(lheight+1,rheight+1);
} print_given_level(root->l
print_given_level(root->r
}
void print_level_order(Node*
{
int h = height(root);
int i;
for(i=1;i<=h;i++)
{
print_given_level(roo
}
}
Q) Spiral Level Order Traversal (Recursively)
Answer = 1, 2,3 7,6,5,4
Ex1) Code
for(i=1;i<=h;i++)
{
if(i%2)
print_level_right_to_left(root,i);
else
print_level_left_to_right(root,i);
}
}
1) Concept :-
At the Odd Level print nodes from right to left
At the Even Level print nodes from left to right
Step 1 (Recursive) :-
1) Traverse the given tree in pre-order/post-order fashion
3) Then recursively invert the Left and Right Subtree of Node x as well
Ex1) Illustration 1
// Inverting the Binary Tree by traversing the tree in a pre-order fashion
void invertBinaryTree1(Node* root)
{
if(root == nullptr)
return;
// Swap the left and right child of the current Node
swap(root->left,root->right);
// Invert Left Subtree of current Node
invertBinaryTree1(root->left);
// Invert Binary Tree of current Node
invertBinaryTree1(root->right);
}
Ex2) Illustration 2
// Inverting the Binary Tree by traversing the tree in a post-order fashion
void invertBinaryTree2(Node* root)
{
if(root==nullptr)
return;
// Invert Left Subtree of current Node
invertBinaryTree2(root->left);
// Invert Binary Tree of current Node
invertBinaryTree2(root->right);
// Swap the left and right child of the current Node
// Swap mtlb mutlaq swap...and not merely swapping their data
swap(root->left,root->right);
}
Ex3) Illustration 3
// Inverting the Binary Tree by traversing the tree in a pre-order fashion
Node* invertBinaryTree1(Node* root)
{
if(root==nullptr)
return root;
// Swap the left and right child of the current Node
// Swap mtlb mutlaq swap...and not merely swapping their data
swap(root->left,root->right);
// Invert Left Subtree of current Node
invertBinaryTree1(root->left);
// Invert Binary Tree of current Node
invertBinaryTree1(root->right);
return root;
}
3) Interesting fact :-
Inverting a Binary Tree Converting a BT to it’s mirror image.
Ex1) Code
// Iterative function to print the left view of a given binary tree
void leftView(Node* root)
{
// return if the tree is empty
if (root == nullptr) {
return;
}
// create an empty queue and enqueue the root node
queue<Node*> q;
q.push(root);
// pointer to store the current node
Node* curr = nullptr;
// loop till queue is empty
while (!q.empty())
{
// calculate the total number of nodes at the current level
int size = q.size();
int i = 0;
// process every node of the current level
// and enqueue their non-empty left, right child
while (i++ < size)
{
curr = q.front();
q.pop();
// if this is the first node of the current level, print it
if (i == 1) {
cout << curr->data << ",";
}
if (curr->left) {
q.push(curr->left);
}
if (curr->right) {
q.push(curr->right);
}
}
}
}
https://www.techiedelight.com/print-bottom-view-of-binary-tree/
Q) Print Bottom View of a BT.
Bottom View = 7, 5, 8, 6.
(horizontal distance —> (node’s valu
-1 —> (7, 4)
0 —> (5, 3)
1 —> (8, 4)
2 —> (6, 3)
1) Think Like
x coord horiz_dis
y coord (node_value, node_level) O
y coord (node_level, node_value)
x coord key , y coord value
// Priniting the contents of the Map prints the Bottom View of the bt
void generateBottomView(Node* node, int dist, int level, map<int, pair<int, int>> &m)
{
// base case: empty tree
if (node == nullptr) {
return;
}
// If the (current level of node) >= (maximum level seen so far) for the same horizontal
// Or if the horizontal distance is seen for the first time, update the map
// Then update the (Curr Node's value, Curr Node's value).
// Bcoz for same hoiz dis , level must be the bottommost(max)
if ( (level >= m[dist].second) || (m.find(dist) == m.end()) )
{
// update value and level for the current distance
m[dist] = { node->data, level };
}
// Recur for the left subtree
// Hence level = level + 1
// Horizontal dist = dist = dist - 1
generateBottomView(node->left, dist - 1, level + 1, m);
// Recur for the Right subtree
// Hence level = level + 1
// Horizontal dist = dist = dist + 1
generateBottomView(node->right, dist + 1, level + 1, m);
}
// Function to print the bottom view of a given binary tree
void printBottomView(Node* root)
{
map<int, pair<int, int>> m;
// perform preorder traversal on the tree and fill the map
generateBottomView(root, 0, 0, m);
// traverse the map and print the bottom view
for (auto it: m) {
cout << it.second.first << " ";
}
}
1) Approach :-
Ht of root = 1 + max(Ht. of left subtree,Ht. of right subtree).
Plus 1 = To include the root also
int height1(Node* node)
{
if(node == NULL)
return 0;
int lheight = height1(node->left);
int rheight = height1(node->right);
return 1 + max(lheight,rheight);
}
1) Approach :-
Ht of root = 1 + max(Ht. of left subtree,Ht. of right subtree).
Plus 1 = To include the root also
int height1(Node* node)
{
if(node == NULL)
return -1;
int lheight = height1(node->left);
int rheight = height1(node->right);
return 1 + max(lheight,rheight);
}
2) Time Complexity :-
Time Complexity = O(n).
Since we are going to each and every node of the BT.
n = No. of nodes in the BT.
if (node->right != nullptr)
rheight = 1 + height(node->right);
// return max(lheight,rheight);
return lheight > rheight ? lheight:rheight;
}
Q) Find the Diameter(width) of a BT
2) Diamter of a Tree
No. of nodes on the longest path containing two leaf nodes.
3) Example 1:-
(4 to 7) (4 2 1 3 5 7) No. of Nodes = 6
(4 to 8) (4 2 1 3 5 8) No. of Nodes = 6
(4 to 6) (4 2 1 3 6) No. of Nodes = 5
(7 to 8) (7 5 8) No. of nodes = 3
(7 to 6) (7 5 3 6) No. of nodes = 4
(8 to 6) (8 5 3 6) No. of nodes = 4
4) Hence in example 1
Diameter of tree = No. of nodes from (4 to 7) = No. of nodes from (4 to 8) = 6.
int diameter1(Node* node)
{
if(node == NULL)
return 0;
int ld = diameter1(node->left);
int rd = diameter1(node->right);
int sp = height1(node->left) + height1(node->right) + 2;
return max(max(ld,rd),sp);// Return max(ld,rd,sp) basically
}
Concept:-
ld = Diamter of the left subtree
rd = Diamter of the right subtree
Time Complexity
Time Complexity = O(n 2 )
There are n nodes in the tree.
For each node … We are calling the height1() function [height1() takes O(n) time ]
Hence we are getting O(n 2 ) time complexity.
See vid. At 38:40
1) Let’s Search 45
45 > 25 Go to right of 25 50 encountered
45 < 50 Go to the left of 50 35 encountered
45 > 35 Go to the right of 35 44 encountered
45 > 44 Go to the right of 44 NULL encountered
Hence 45 is not present in the BST
2) Let’s search 22
22 < 25 Go to the left of 25 15 encountered
22 > 15 Go to the right of 15 22 encountered
Hence we have got 22 It is present to the left of 15
Q)
1) T
2) I
cont
i
3) I
valu
4) S
N
Ill1
// F
// I
Node
{
}
return curr ; 1) T
}
3) Average Case :-
Occurs for Ht. Balanced BST’s (AVL,RB,and normal balanced BST’s).
4) Worst Case :-
Occurrs for Skewed BST’s .
Bcoz for Skewed BST’s Ht becomes n (h = n).
Hence Time Complexity becomes O(n).
Also BST’s are not guaranteed to be self balanced (Considering the properties of
BST).
5) BST in Worst Case (i.e Skewed BST’s) :-
Has O(n) Time complexity of operations
Hence are no more efficient than a regular linked list.
Hence works like an linear unordered array/list.
1)
1) AVL Trees are a special Kind of BST’s
2)
2) AVL Tree is a BST wherein
ht. of left_subtree and right_subtree of every node differs by atmost one
They are a special kind of BST wherein b.f of every node = {-1,0,1}
4)
Ex1) Concept 😊 😊 1)
2)