Chap - 4] Tree
4.1] Introduction
A tree is also one of the data structures that represent hierarchical data.
The Tree data structure is similar to Linked Lists in that each node
contains data and can be linked to other nodes.
We have already seen data structures like Arrays, Linked Lists, Stacks,
and Queues. These are all linear structures, which means that each
element follows directly after another in a sequence. But Trees are
different. In a Tree,all elements are not arranges in a sequence
and a single element can have multiple 'next' elements.
The data structure is called a "tree" because it looks like a tree, where
root is first node of tree which is divided into sub parts, as shown in
following fig.
The root is at the top, and its branches are moving in a downward
direction. Therefore, we can say that the Tree data structure is an efficient
way of storing the data in a hierarchical way.
Binary Trees :
A Binary Tree is a type of tree data structure where each node can have a
maximum of two child nodes, a left child node and a right child node.
4.2 Terminology of Binary tree
1 Root node
2 Edges
3 Nodes
4 Leaf nodes
5 Child nodes
6 Parent nodes
7 Tree height (h=3)
8 Tree size (no.of nodes i.e 15)
9. Depth of tree
1. Root
It is the topmost node of a tree.
2. Node
A node is an entity that contains a key or value and pointers to its
child nodes.
The node having at least a child node is called an internal node.
3. Edge
It is the link between any two nodes.
4. Height of a Node
The height of a node is the number of edges from the node to the
leaf node (ie. the longest path from the node to a leaf node).
5. Depth of a Node
The depth of a node is the number of edges from the root to the node.
6. Height of a Tree
The height of a Tree is the height of the root node or the depth
of the deepest node.
7.Internal Node:(parent node):
A parent node has links to its child nodes. Another word for a parent node
is internal node.
A node can have one, or many child nodes.
8.leaf nodes: (external nodes /leaves node)
The last nodes of each path are called leaf nodes or external nodes
/leaves node that do not contain a link/pointer to child nodes.
9.Height of Tree :
The tree height is the maximum number of edges from the root node to a leaf
node. The height of the tree above is 2.
10.Size of TREE:
The tree size is the number of nodes in the tree.
4.3 Types of Binary tree :
1. Full Binary Tree
A binary tree is said to be a full binary tree when each internal
node has zero or two children:
2. Perfect Binary Tree
A perfect binary tree is a special type of binary tree in which all the
leaf nodes are at the same level and each internal node has two
children:
3. Complete Binary Tree
A binary tree is referred to as a complete binary tree when all of its
levels are completely filled.
The only exception is possibly the lowest level which are filled from as left
as possible.
4. Degenerate or Pathological Tree
A degenerate or pathological tree is a type of binary tree in which
each internal node has a single child, either the left child or the
right child:
5. Skewed Binary Tree
A binary tree is said to be a skewed binary tree if all of its internal
nodes have exactly one child, and either left children or right
children dominate the tree.
In particular, there exist two types of skewed binary trees: left-
skewed binary tree and the right-skewed binary tree:
6. Balanced Binary Tree
A balanced binary tree is also a special type of binary tree in
which the difference of height between the left and the right
subtrees for each node is at most one:
4.4 Traversing of binary tree
The term 'tree traversal' means traversing or visiting each node of a tree.
In linear data structure There is a single way to traverse the such as
linked list, queue, and stack.
In the Tree, there are multiple ways to traverse a tree that are listed as
follows
o Preorder traversal
o Inorder traversal
o Postorder traversal
1] Preorder traversal
This technique follows the 'root left right' policy.
It means that, first root node is visited after that the left subtree is
visited, and finally, right subtree is recursively traversed.
The root node is traversed before (or pre) the left and right subtree,
it is called preorder traversal.
Example
Now, let's see the example of the preorder traversal technique.
Now, start applying the preorder traversal on the above tree. First, we
traverse the root node A; after that, move to its left subtree B, which will
also be traversed in preorder.
So, for left subtree B, first, the root node B is traversed itself; after
that, its left subtree D is traversed. Since node D and E does not have any
children. traversal of the left subtree of root node A is completed.
Now, move towards the right subtree of root node A that is C. So, for
right subtree C, first the root node C has traversed itself; after that, its left
subtree F is traversed. Since node F and G does not have any children,
traversal of the right subtree of root node A is completed.
So, the output of the preorder traversal of the above tree is -
A→B→D→E→C→F→G
## Write a program for preorder traversal.
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode {
char data;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
TreeNode* createNewNode(char data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
void preOrderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
printf("%c, ", root->data);
preOrderTraversal(root->left);
preOrderTraversal(root->right);
}
int main() {
TreeNode* root = createNewNode('R');
TreeNode* nodeA = createNewNode('A');
TreeNode* nodeB = createNewNode('B');
TreeNode* nodeC = createNewNode('C');
TreeNode* nodeD = createNewNode('D');
TreeNode* nodeE = createNewNode('E');
TreeNode* nodeF = createNewNode('F');
TreeNode* nodeG = createNewNode('G');
root->left = nodeA;
root->right = nodeB;
nodeA->left = nodeC;
nodeA->right = nodeD;
nodeB->left = nodeE;
nodeB->right = nodeF;
nodeF->left = nodeG;
// Traverse
preOrderTraversal(root);
free(nodeG);
free(nodeF);
free(nodeE);
free(nodeB);
free(nodeC);
free(nodeD);
free(nodeA);
free(root);
return 0;
}
C result:
R, A, C, D, B, E, F, G,
2] Postorder traversal
This technique follows the 'left-right root' policy.
It means that the first left subtree of the root node is traversed, after
that traverses the right subtree, and finally, the root node is
traversed.
he root node is traversed after (or post) the left and right subtree, it is
called postorder traversal.
So, in a postorder traversal, each node is visited after both of its subtrees.
Example
Now, let's see the example of the postorder traversal technique.
First, we traverse the left subtree B that will be traversed in postorder.
After that, we will traverse the right subtree C in postorder. And finally, the
root node of the above tree, i.e., A, is traversed.
So, for left subtree B, first, its left subtree D is traversed. Since node
D and E does not have any children move to the root node B. After
traversing node B, the traversal of the left subtree of root node A is
completed.
Now, move towards the right subtree of root node A that is C. first its
left subtree F is traversed. Since node F and G does not have any children.
The traversal of the right subtree of root node A is completed.
At last, traverse the root node of a given tree, i.e., A.
So, the output of the postorder traversal of the above tree is -
D→E→B→F→G→C→A
## Write a program for postorder traversal.
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode {
char data;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
TreeNode* createNewNode(char data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
void postOrderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
postOrderTraversal(root->left);
postOrderTraversal(root->right);
printf("%c, ", root->data);
}
int main() {
TreeNode* root = createNewNode('R');
TreeNode* nodeA = createNewNode('A');
TreeNode* nodeB = createNewNode('B');
TreeNode* nodeC = createNewNode('C');
TreeNode* nodeD = createNewNode('D');
TreeNode* nodeE = createNewNode('E');
TreeNode* nodeF = createNewNode('F');
TreeNode* nodeG = createNewNode('G');
root->left = nodeA;
root->right = nodeB;
nodeA->left = nodeC;
nodeA->right = nodeD;
nodeB->left = nodeE;
nodeB->right = nodeF;
nodeF->left = nodeG;
// Traverse
postOrderTraversal(root);
free(nodeG);
free(nodeF);
free(nodeE);
free(nodeB);
free(nodeC);
free(nodeD);
free(nodeA);
free(root);
return 0;
}
C result:
C, D, A, E, G, F, B, R,
3] Inorder traversal
This technique follows the 'left root right' policy.
It means that first left subtree is visited after that root node is
traversed, and finally, the right subtree is traversed.
he root node is traversed between the left and right subtree, it is called
inorder traversal.
Example
Now, let's see the example of the Inorder traversal technique.
Now, start applying the inorder traversal on the above tree. First, we
traverse the left subtree B that will be traversed in inorder. After that, we
will traverse the root node A. And finally, the right subtree C is traversed in
inorder.
So, for left subtree B, first, its left subtree D is traversed. Since node
D does not have any children, so after traversing it, node B will be
traversed, and at last, right subtree of node B, that is E, is traversed. So
traversal of the left subtree of root node A is completed.
After that, traverse the root node of a given tree, i.e., A.
At last, move towards the right subtree of root node A that is C. So,
for right subtree C; first, its left subtree F is traversed. Since node F does
not have any children, node C will be traversed, and at last, a right subtree
of node C, that is, G, is traversed.
The output of the inorder traversal of the above tree is -
D→B→E→A→F→C→G
## Write a program for Inorder traversal.
#include <stdio.h>
#include <stdlib.h>
typedef struct TreeNode {
char data;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
TreeNode* createNewNode(char data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
void inOrderTraversal(TreeNode* root) {
if (root == NULL) {
return;
}
inOrderTraversal(root->left);
printf("%c, ", root->data);
inOrderTraversal(root->right);
}
int main() {
TreeNode* root = createNewNode('R');
TreeNode* nodeA = createNewNode('A');
TreeNode* nodeB = createNewNode('B');
TreeNode* nodeC = createNewNode('C');
TreeNode* nodeD = createNewNode('D');
TreeNode* nodeE = createNewNode('E');
TreeNode* nodeF = createNewNode('F');
TreeNode* nodeG = createNewNode('G');
root->left = nodeA;
root->right = nodeB;
nodeA->left = nodeC;
nodeA->right = nodeD;
nodeB->left = nodeE;
nodeB->right = nodeF;
nodeF->left = nodeG;
// Traverse
inOrderTraversal(root);
free(nodeG);
free(nodeF);
free(nodeE);
free(nodeB);
free(nodeC);
free(nodeD);
free(nodeA);
free(root);
return 0;
}
C result:
C, A, D, R, E, B, G, F,
4.5] Header Nodes
A header node is a special node that is found at the beginning of the list.
A list that contains this type of node is called the header-linked list.
In a header linked list, HEAD points to the header node instead of
the first node of the list.
Header-linked lists are commonly used in addition, multiplication operations .
The header node does not represent an item in the linked list.
This data part of this node is generally used to hold any global
information about the entire linked list i.e. No. of node (length of
linked list),Largest value in linked list,Smallest value in linked list
etc.as shown in fig total no. of node is 4, Largest value is 99 in
linked list,Smallest value is 5 in list.
The next part of the header node points to the first node in the list.
Threads
In the linked representation of binary trees, n o. of fields contain
NULL values which results in wastage of storage space.
If the binary tree consist of n nodes then n+1 link fields contains NULL
values.
So in order to effectively manage the space, a method was
used by Perlis and Thornton in which the NULL links are
replaced with special links known as threads.
Such binary tree with threads are known as threaded binary
trees.
A threaded binary tree is a type of binary tree data structure where
the empty left and right child pointers in a binary tree are replaced
with threads that link nodes directly to their in-order predecessor or
successor, thereby providing a way to traverse the tree without
using recursion or a stack.As shown in following fig.
Each node in a threaded binary tree either contains a link to
its child node or thread to other nodes in the tree.
4.6 General Tree Introductions
The general tree is one of the types of tree data structure.
In the general tree, a node can have either 0 or maximum
n number of nodes.
There is no restriction imposed on the degree of the node
(the number of nodes that a node can contain).
The topmost node in a general tree is known as a root node.
The children of the parent node are known as subtrees.
There can be n number of subtrees in a general tree.
In the general tree, the subtrees are unordered as the nodes in
the subtree cannot be ordered.
Every non-empty tree has a downward edge, and these
edges are connected to the nodes known as child nodes.
The root node is labeled with level 0.
The nodes that have the same parent are known as siblings.