Data Structures - Trees Notes
Data Structures - Trees Notes
Binary Trees: The tree in C is a non-linear data structure, i.e. The elements are not stored
sequentially, and in the tree in C, they are present in levels.
i. A binary tree in C is a data structure in which every node can have a maximum of
two children nodes.
ii. Children nodes are labeled as right and left child. Each node in the binary tree
contains a value and two pointers pointing to the children.
iii. The topmost node of the binary tree is called the root node and the bottom-most
nodes of the binary tree are called leaf nodes.
iv. The height of a binary tree is calculated by taking the longest path between the
root and the leaf node.
Tree Terminologies:-
1. Root:- A root is a node without a parent.
2. Siblings:- Siblings mean that nodes which have the same parent node.
3. Internal Node:- Internal Node means that a node which has at least a single child.
4. External Node:- External Node means that a node which has no children. It is also
known as leaf.
5. Ancestors:- Ancestors include the parent, grandparent and so on of a node.
6. Descendants:- Descendants are the opposite of ancestors, It includes the child,
grandchild and so on of a node.
7. Edge:- An edge means a connection between one node to another node.
8. Path:- Path is a combination of nodes and edges connected with each other.
There are four types of Binary tree:
The full binary tree is also known as a strict binary tree. The tree can only be considered as
the full binary tree if each node must contain either 0 or 2 children. The full binary tree can
also be defined as the tree in which each node must contain 2 children except the leaf nodes.
The complete binary tree is a tree in which all the nodes are completely filled except the last
level. In the last level, all the nodes must be as left as possible. In a complete binary tree, the
nodes should be added from the left.
o Perfect Binary Tree
A tree is a perfect binary tree if all the internal nodes have 2 children, and all the leaf nodes
are at the same level.
The degenerate binary tree is a tree in which all the internal nodes have only one children.
A skewed binary tree is a pathological/degenerate tree in which the tree is either dominated
by the left nodes or the right nodes. Thus, there are two types of skewed binary tree: left-
skewed binary tree and right-skewed binary tree.
o Balanced Binary Tree
It is a type of binary tree in which the difference between the height of the left and the
right subtree for each node is either 0 or 1.
A Binary tree is implemented with the help of pointers. The first node in the tree is
represented by the root pointer. Each node in the tree consists of three parts, i.e.,
o Data
o left pointer and
o right pointer.
To create a binary tree, we first need to create the node.
In C, we can represent a tree node using structures. In other languages, we can use classes as
part of their OOP feature. Below is an example of a tree node with integer data.
// Structure of each node of the tree
struct node {
int data;
struct node* left;
struct node* right;
};
Tree Traversal using Depth-First Search (DFS) algorithm can be further classified into
three categories:
Preorder Traversal-
100 , 20 , 10 , 30 , 200 , 150 , 300
Inorder Traversal-
10 , 20 , 30 , 100 , 150 , 200 , 300
Postorder Traversal-
10 , 30 , 20 , 150 , 300 , 200 , 100
Tree Traversal using Breadth-First Search (BFS) algorithm can be further classified into
one category:
• Level Order Traversal: Visit nodes level-by-level and left-to-right fashion at the
same level. Here, the traversal is level-wise. It means that the most left child
has traversed first and then the other children of the same level from left to
right have traversed.
Let us traverse the following tree with all four traversal methods:
Binary Tree
Example:
// Tree traversal in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int item;
struct node* left;
struct node* right;
};
// Inorder traversal
void inorderTraversal(struct node* root) {
if (root == NULL) return;
inorderTraversal(root->left);
printf("%d ->", root->item);
inorderTraversal(root->right);
}
// Preorder traversal
void preorderTraversal(struct node* root) {
if (root == NULL) return;
printf("%d ->", root->item);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
// Postorder traversal
void postorderTraversal(struct node* root) {
if (root == NULL) return;
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%d ->", root->item);
}
return newNode;
}
int main() {
struct node* root = createNode(1);
insertLeft(root, 2);
insertRight(root, 3);
insertLeft(root->left, 4);
printf("Inorder traversal \n");
inorderTraversal(root);
printf("\nPreorder traversal \n");
preorderTraversal(root);
printf("\nPostorder traversal \n");
postorderTraversal(root);
}
Search Trees:
A tree is a kind of data structure that is used to represent the data in hierarchical form. It can
be defined as a collection of objects or entities called as nodes that are linked together to
simulate a hierarchy. Tree is a non-linear data structure as the data in a tree is not stored
linearly or sequentially.
o Searching an element in the Binary search tree is easy as we always have a hint that
which subtree has the desired element.
o As compared to array and linked lists, insertion and deletion operations are faster in
BST.
• Search Operation
In Search, we have to find a specific element in the data structure. This searching operation
becomes simpler in binary search trees because here elements are stored in sorted order.
The steps of searching a node in Binary Search tree are listed as follows -
1. First, compare the element to be searched with the root element of the tree.
2. If root is matched with the target element, then return the node's location.
3. If it is not matched, then check whether the item is less than the root element, if it is
smaller than the root element, then move to the left subtree.
4. If it is larger than the root element, then move to the right subtree.
5. Repeat the above procedure recursively until the match is found.
6. If the element is not found or not present in the tree, then return NULL.
Step 1:
Step2:
Step3:
• Deletion in Binary Search tree
In a binary search tree, we must delete a node from the tree by keeping in mind that the
property of BST is not violated. To delete a node from BST, there are three possible situations
occur -
It is the simplest case to delete a node in BST. Here, we have to replace the leaf node with
NULL and simply free the allocated space.
We can see the process to delete a leaf node from BST in the below image. In below image,
suppose we have to delete node 90, as the node to be deleted is a leaf node, so it will be
replaced with NULL, and the allocated space will free.
We can see the process of deleting a node with one child from BST in the below image. In the
below image, suppose we have to delete the node 79, as the node to be deleted has only one
child, so it will be replaced with its child 55.
So, the replaced node 79 will now be a leaf node that can be easily deleted.
This case of deleting a node in BST is a bit complex among other two cases. In such a case, the
steps to be followed are listed as follows -
The inorder successor is required when the right child of the node is not empty. We can obtain
the inorder successor by finding the minimum element in the right child of the node.
We can see the process of deleting a node with two children from BST in the below image. In
the below image, suppose we have to delete node 45 that is the root node, as the node to be
deleted has two children, so it will be replaced with its inorder successor. Now, node 45 will
be at the leaf of the tree so that it can be deleted easily.
Now let's understand how insertion is performed on a binary search tree.
A new key in BST is always inserted at the leaf. To insert an element in BST, we have to start
searching from the root node; if the node to be inserted is less than the root node, then search
for an empty location in the left subtree. Else, search for the empty location in the right
subtree and insert the data. Insert in BST is similar to searching, as we always have to maintain
the rule that the left subtree is smaller than the root, and right subtree is larger than the root.
Now, let's see the process of inserting a node into BST using an example.
Example Program:
// Binary Search Tree operations in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int key;
struct node *left, *right;
};
// Create a node
struct node *newNode(int item) {
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// Inorder Traversal
void inorder(struct node *root) {
if (root != NULL) {
// Traverse left
inorder(root->left);
// Traverse root
printf("%d -> ", root->key);
// Traverse right
inorder(root->right);
}
}
// Insert a node
struct node *insert(struct node *node, int key) {
// Return a new node if the tree is empty
if (node == NULL) return newNode(key);
// Deleting a node
struct node *deleteNode(struct node *root, int key) {
// Return if the tree is empty
if (root == NULL) return root;
else {
// If the node is with only one child or no child
if (root->left == NULL) {
struct node *temp = root->right;
free(root);
return temp;
} else if (root->right == NULL) {
struct node *temp = root->left;
free(root);
return temp;
}
// Driver code
int main() {
struct node *root = NULL;
root = insert(root, 8);
root = insert(root, 3);
root = insert(root, 1);
root = insert(root, 6);
root = insert(root, 7);
root = insert(root, 10);
root = insert(root, 14);
root = insert(root, 4);