Unit 5
Unit 5
In the above structure, each node is labeled with some number. Each arrow shown in the
above figure is known as a link between the two nodes.
Root: The root node is the topmost node in the tree hierarchy. In other words,
the root node is the one that doesn't have any parent. In the above structure,
node numbered 1 is the root node of the tree. If a node is directly linked to some
other node, it would be called a parent-child relationship.
Child node: If the node is a descendant of any node, then the node is known as a
child node.
Parent: If the node contains any sub-node, then that node is said to be the parent
of that sub-node.
Sibling: The nodes that have the same parent are known as siblings.
Leaf Node:- The node of the tree, which doesn't have any child node, is called a
leaf node. A leaf node is the bottom-most node of the tree. There can be any
number of leaf nodes present in a general tree. Leaf nodes can also be called
external nodes.
Internal nodes: A node has atleast one child node known as an internal
Ancestor node:- An ancestor of a node is any predecessor node on a path from
the root to that node. The root node doesn't have any ancestors. In the tree
shown in the above image, nodes 1, 2, and 5 are the ancestors of node 10.
Descendant: The immediate successor of the given node is known as a
descendant of a node. In the above figure, 10 is the descendant of node 5.
Recursive data structure: The tree is also known as a recursive data structure. A
tree can be defined as recursively because the distinguished node in a tree data
structure is known as a root node. The root node of the tree contains a link to all
the roots of its subtrees. The left subtree is shown in the yellow color in the
below figure, and the right subtree is shown in the red color. The left subtree can
be further split into subtrees shown in three different colors. Recursion means
reducing something in a self-similar manner. So, this recursive property of the
tree data structure is implemented in various applications.
Number of edges: If there are n nodes, then there would n-1 edges. Each arrow
in the structure represents the link or path. Each node, except the root node, will
have atleast one incoming link known as an edge. There would be one link for the
parent-child relationship.
Depth of node x: The depth of node x can be defined as the length of the path
from the root to the node x. One edge contributes one-unit length in the path.
So, the depth of node x can also be defined as the number of edges between the
root node and the node x. The root node has 0 depth.
Height of node x: The height of node x can be defined as the longest path from
the node x to the leaf node.
Based on the properties of the Tree data structure, trees are classified into various
categories.
Implementation of Tree
The tree data structure can be created by creating the nodes dynamically with the help of
the pointers. The tree in the memory can be represented as shown below:
The above figure shows the representation of the tree data structure in the memory. In the
above structure, the node contains three fields. The second field stores the data; the first
field stores the address of the left child, and the third field stores the address of the right
child.
1. struct node
2. {
3. int data;
4. struct node *left;
5. struct node *right;
6. }
The above structure can only be defined for the binary trees because the binary tree can
have utmost two children, and generic trees can have more than two children. The
structure of the node for generic trees would be different as compared to the binary tree.
Applications of trees
General tree: 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.
Binary tree
: Here, binary name itself suggests two numbers, i.e., 0 and 1. In a binary tree,
each node in a tree can have utmost two child nodes. Here, utmost means
whether the node has 0 nodes, 1 node or 2 nodes.
: Binary search tree is a non-linear data structure in which one node is connected
to n number of nodes. It is a node-based data structure. A node can be
represented in a binary search tree with three fields, i.e., data part, left-child, and
right-child. A node can be connected to the utmost two child nodes in a binary
search tree, so the node contains two pointers (left child and right child pointer).
Every node in the left subtree must contain a value less than the value of the root
node, and the value of each node in the right subtree must be bigger than the
value of the root node.
A node can be created with the help of a user-defined data type known as struct, as
shown below:
1. struct node
2. {
3. int data;
4. struct node *left;
5. struct node *right;
6. }
The above is the node structure with three fields: data field, the second field is the left
pointer of the node type, and the third field is the right pointer of the node type.
Binary Tree
The Binary tree means that the node can have maximum two children. Here, binary name itself
suggests that 'two'; therefore, each node can have either 0, 1 or 2 children.
The above tree is a binary tree because each node contains the utmost two children. The logical
representation of the above tree is given below:
In the above tree, node 1 contains two pointers, i.e., left and a right pointer pointing to the left
and right node respectively. The node 2 contains both the nodes (left and right node); therefore, it
has two pointers (left and right). The nodes 3, 5 and 6 are the leaf nodes, so all these nodes
contain NULL pointer on both left and right parts.
As we know that,
n = 2h+1 -1
n+1 = 2h+1
log2(n+1) = log2(2h+1)
log2(n+1) = h+1
h = log2(n+1) - 1
As we know that,
n = h+1
h= n-1
In the above tree, we can observe that each node is either containing zero or two children;
therefore, it is a Full Binary tree.
The number of leaf nodes is equal to the number of internal nodes plus 1. In the above example,
the number of internal nodes is 5; therefore, the number of leaf nodes is equal to 6.
The maximum number of nodes is the same as the number of nodes in the binary tree, i.e., 2h+1 -
1.
The minimum number of nodes in the full binary tree is 2*h-1.
The minimum height of the full binary tree is log2(n+1) - 1.
The maximum height of the full binary tree can be computed as:
n= 2*h - 1
n+1 = 2*h
h = n+1/2
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.
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., data, left pointer and right
pointer. To create a binary tree, we first need to create the node. We will create the node of user-
defined as shown below:
struct node
1. {
2. int data,
3. struct node *left, *right;
4. }
In the above structure, data is the value, left pointer contains the address of the left node, and
right pointer contains the address of the right node.
The above code is calling the create() function recursively and creating new node on each
recursive call. When all the nodes are created, then it forms a binary tree structure. The process
of visiting the nodes is known as tree traversal.
A binary search tree follows some order to arrange the elements. In a Binary search tree, the
value of left node must be smaller than the parent node, and the value of right node must be
greater than the parent node. This rule is applied recursively to the left and right subtrees of the
root.
Let's understand the concept of Binary search tree with an example.
In the above figure, we can observe that the root node is 40, and all the nodes of the left subtree
are smaller than the root node, and all the nodes of the right subtree are greater than the root
node.
Similarly, we can see the left child of root node is greater than its left child and smaller than its
right child. So, it also satisfies the property of binary search tree. Therefore, we can say that the
tree in the above image is a binary search tree.
Suppose if we change the value of node 35 to 55 in the above tree, check whether the tree will be
binary search tree or not.
In the above tree, the value of root node is 40, which is greater than its left child 30 but smaller
than right child of 30, i.e., 55. So, the above tree does not satisfy the property of Binary search
tree. Therefore, the above tree is not a binary search tree.
Searching an element in the Binary search tree is easy as we always have a hint that which
subtree has the desired element.
As compared to array and linked lists, insertion and deletion operations are faster in BST.
Example of creating a binary search tree
Now, let's see the creation of binary search tree using an example.
Suppose the data elements are - 45, 15, 79, 90, 10, 55, 12, 20, 50
First, we have to insert 45 into the tree as the root of the tree.
Then, read the next element; if it is smaller than the root node, insert it as the root of the left
subtree, and move to the next element.
Otherwise, if the element is larger than the root node, then insert it as the root of the right
subtree.
Now, let's see the process of creating the Binary search tree using the given data element. The
process of creating the BST is shown below -
As 15 is smaller than 45, so insert it as the root node of the left subtree.
As 79 is greater than 45, so insert it as the root node of the right subtree.
Step 4 - Insert 90.
90 is greater than 45 and 79, so it will be inserted as the right subtree of 79.
55 is larger than 45 and smaller than 79, so it will be inserted as the left subtree of 79.
Step 7 - Insert 12.
12 is smaller than 45 and 15 but greater than 10, so it will be inserted as the right subtree of 10.
20 is smaller than 45 but greater than 15, so it will be inserted as the right subtree of 15.
Step 9 - Insert 50.
50 is greater than 45 but smaller than 79 and 55. So, it will be inserted as a left subtree of 55.
Now, the creation of binary search tree is completed. After that, let's move towards the
operations that can be performed on Binary search tree.
We can perform insert, delete and search operations on the binary search tree.
Searching means to find or locate a specific element or node in a data structure. In Binary search
tree, searching a node is easy because elements in BST are stored in a specific 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.
Now, let's understand the searching in binary tree using an example. We are taking the binary
search tree formed above. Suppose we have to find node 20 from the below tree.
Step1:
Step2:
Step3:
Now, let's see the algorithm to search an element in the Binary search tree.
Now let's understand how the deletion is performed on a binary search tree. We will also see an
example to delete an element from the given 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.
In this case, we have to replace the target node with its child, and then delete the child node. It
means that after replacing the target node with its child node, the child node will now contain the
value to be deleted. So, we simply have to replace the child node with NULL and free up the
allocated space.
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.
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.
The complexity of the Binary Search tree
Let's see the time and space complexity of the Binary search tree. We will see the time
complexity for insertion, deletion, and searching operations in best case, average case, and worst
case.
1. Time Complexity
Operations Best case time complexity Average case time complexity Worst case time complexity
2. Space Complexity
Operations Space complexity
Insertion O(n)
Deletion O(n)
Search O(n)
Preorder traversal
Inorder traversal
Postorder traversal
So, in this article, we will discuss the above-listed techniques of traversing a tree. Now, let's start
discussing the ways of tree traversal.
Preorder traversal
This technique follows the 'root left right' policy. It means that, first root node is visited after that
the left subtree is traversed recursively, and finally, right subtree is recursively traversed. As the
root node is traversed before (or pre) the left and right subtree, it is called preorder traversal.
So, in a preorder traversal, each node is visited before both of its subtrees.
The applications of preorder traversal include -
Algorithm
Example
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 does not have any children, move to right subtree E. As node E also
does not have any children, 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. So, for right subtree C, first the
root node C has traversed itself; after that, its left subtree F is traversed. Since node F does not
have any children, move to the right subtree G. As node G also does not have any children,
traversal of the right subtree of root node A is completed.
Therefore, all the nodes of the tree are traversed. So, the output of the preorder traversal of the
above tree is -
A→B→D→E→C→F→G
To know more about the preorder traversal in the data structure, you can follow the link Preorder
traversal.
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 recursively traverses the right subtree, and finally, the root node is
traversed. As the 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.
Algorithm
Example
So, for left subtree B, first, its left subtree D is traversed. Since node D does not have any
children, traverse the right subtree E. As node E also 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. So, for right subtree C, first its left
subtree F is traversed. Since node F does not have any children, traverse the right subtree G. As
node G also does not have any children, therefore, finally, the root node of the right subtree, i.e.,
C, is traversed. 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. After traversing the root node, the postorder
traversal of the given tree is completed.
Therefore, all the nodes of the tree are traversed. So, the output of the postorder traversal of the
above tree is -
D→E→B→F→G→C→A
To know more about the postorder traversal in the data structure, you can follow the link
Postorder traversal.
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. As the root node is traversed
between the left and right subtree, it is named inorder traversal.
So, in the inorder traversal, each node is visited in between of its subtrees.
Algorithm
Example
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. Node E also does not have any children; therefore, the traversal of the left
subtree of root node A is completed.
As all the nodes of the tree are traversed, the inorder traversal of the given tree is completed. The
output of the inorder traversal of the above tree is -
D→B→E→A→F→C→G
To know more about the inorder traversal in data structure, you can follow the link Inorder
Traversal.
The time complexity of tree traversal techniques discussed above is O(n), where 'n' is the size of
binary tree.
Whereas the space complexity of tree traversal techniques discussed above is O(1) if we do not
consider the stack size for function calls. Otherwise, the space complexity of these techniques is
O(h), where 'h' is the tree's height.
36.
37. int choice;
38. scanf("%d",&choice);
39. switch (choice)
40. {
41. case 1 :
42. printf("\nEnter the value to be inserted\n");
43. scanf("%d",&data);
44. insert(&ptr,data);
45. break;
46. case 2 :
47. printf("\nPreorder Traversal of the Binary Tree::\n");
48. preorder(ptr);
49. break;
50. case 3 :
51. printf("\nInorder Traversal of the Binary Tree::\n");
52. inorder(ptr);
53. break;
54. case 4 :
55. printf("\nPostorder Traversal of the Binary Tree::\n");
56. postorder(ptr);
57. break;
58. default :
59. printf("Wrong Entry\n");
60. break;
61. }
62.
63. printf("\nDo you want to continue (Type y or n)\n");
64. scanf(" %c",&ch);
65. } while (ch == 'Y'|| ch == 'y');
66.
67.
68. // printf("\nProgram for Tree Traversal\n");
69. // printf("Enter the number of nodes to add to the tree.<BR>\n");
70. // scanf("%d",&no);
71.
72. // for(i=0;i<no;i++)
73. // {
74. // printf("Enter the item\n");
75. // scanf("%d",&num);
76. // insert(&ptr,num);
77. // }
78.
79. // //getch();
80. // printf("\nINORDER TRAVERSAL\n");
81. // inorder(ptr);
82.
83. // printf("\nPREORDER TRAVERSAL\n");
84. // preorder(ptr);
85.
86. // printf("\nPOSTORDER TRAVERSAL\n");
87. // postorder(ptr);
88.
89. }
90.
91. void insert(struct node **p,int num)
92. {
93. if((*p)==NULL)
94. {
95. printf("Leaf node created.");
96. (*p)=malloc(sizeof(struct node));
97. (*p)->left = NULL;
98. (*p)->right = NULL;
99. (*p)->data = num;
100. return;
101. }
102. else
103. {
104. if(num==(*p)->data)
105. {
106. printf("\nREPEATED ENTRY ERROR VALUE REJECTED\n");
107. return;
108. }
109. if(num<(*p)->data)
110. {
111. printf("\nDirected to left link.\n");
112. insert(&((*p)->left),num);
113. }
114. else
115. {
116. printf("Directed to right link.\n");
117. insert(&((*p)->right),num);
118. }
119. }
120. return;
121. }
122.
123. void inorder(struct node *p)
124. {
125. if(p!=NULL)
126. {
127. inorder(p->left);
128. printf("%d ",p->data);
129. inorder(p->right);
130. }
131. else
132. return;
133. }
134.
135. void preorder(struct node *p)
136. {
137. if(p!=NULL)
138. {
139. printf("%d ",p->data);
140. preorder(p->left);
141. preorder(p->right);
142. }
143. else
144. return;
145. }
146.
147. void postorder(struct node *p)
148. {
149. if(p!=NULL)
150. {
151. postorder(p->left);
152. postorder(p->right);
153. printf("%d ",p->data);
154. }
155. else
156. return;
157. }
Output:
Graph
A graph can be defined as group of vertices and edges that are used to connect these vertices. A
graph can be seen as a cyclic tree, where the vertices (Nodes) maintain any complex relationship
among them instead of having parent child relationship.
Definition
A graph G can be defined as an ordered set G(V, E) where V(G) represents the set of vertices
and E(G) represents the set of edges which are used to connect these vertices.
A Graph G(V, E) with 5 vertices (A, B, C, D, E) and six edges ((A,B), (B,C), (C,E), (E,D),
(D,B), (D,A)) is shown in the following figure.
Directed and Undirected Graph
A graph can be directed or undirected. However, in an undirected graph, edges are not associated
with the directions with them. An undirected graph is shown in the above figure since its edges
are not attached with any of the directions. If an edge exists between vertex A and B then the
vertices can be traversed from B to A as well as A to B.
In a directed graph, edges form an ordered pair. Edges represent a specific path from some vertex
A to another vertex B. Node A is called initial node while node B is called terminal node.
Graph Terminology
Path
A path can be defined as the sequence of nodes that are followed in order to reach some terminal
node V from the initial node U.
Closed Path
A path will be called as closed path if the initial node is same as terminal node. A path will be
closed path if V0=VN.
Simple Path
If all the nodes of the graph are distinct with an exception V 0=VN, then such path P is called as
closed simple path.
Cycle
A cycle can be defined as the path which has no repeated edges or vertices except the first and
last vertices.
Connected Graph
A connected graph is the one in which some path exists between every two vertices (u, v) in V.
There are no isolated nodes in connected graph.
Complete Graph
A complete graph is the one in which every node is connected with all other nodes. A complete
graph contain n(n-1)/2 edges where n is the number of nodes in the graph.
Weighted Graph
In a weighted graph, each edge is assigned with some data such as length or weight. The weight
of an edge e can be given as w(e) which must be a positive (+) value indicating the cost of
traversing the edge.
Digraph
A digraph is a directed graph in which each edge of the graph is associated with some direction
and the traversing can be done only in the specified direction.
Loop
An edge that is associated with the similar end points can be called as Loop.
Adjacent Nodes
If two nodes u and v are connected via an edge e, then the nodes u and v are called as neighbours
or adjacent nodes.
A degree of a node is the number of edges that are connected with that node. A node with degree
0 is called as isolated node.
Graph representation
In this article, we will discuss the ways to represent the graph. By Graph representation, we
simply mean the technique to be used to store some graph into the computer's memory.
A graph is a data structure that consist a sets of vertices (called nodes) and edges. There are two
ways to store Graphs into the computer's memory:
In sequential representation, an adjacency matrix is used to store the graph. Whereas in linked
list representation, there is a use of an adjacency list to store the graph.
Now, let's start discussing the ways of representing a graph in the data structure.
Sequential representation
If adj[i][j] = w, it means that there is an edge exists from vertex i to vertex j with weight w.
An entry Aij in the adjacency matrix representation of an undirected graph G will be 1 if an edge
exists between Vi and Vj. If an Undirected Graph G consists of n vertices, then the adjacency
matrix for that graph is n x n, and the matrix A = [aij] can be defined as -
aij = 0 {Otherwise}
It means that, in an adjacency matrix, 0 represents that there is no association exists between the
nodes, whereas 1 represents the existence of a path between two edges.
If there is no self-loop present in the graph, it means that the diagonal entries of the adjacency
matrix will be 0.
There exist different adjacency matrices for the directed and undirected graph. In a directed
graph, an entry Aij will be 1 only when there is an edge directed from Vi to Vj.
In a directed graph, edges represent a specific path from one vertex to another vertex. Suppose a
path exists from vertex A to another vertex B; it means that node A is the initial node, while node
B is the terminal node.
Consider the below-directed graph and try to construct the adjacency matrix of it.
In the above graph, we can see there is no self-loop, so the diagonal entries of the adjacent matrix
are 0.
Adjacency matrix for a weighted directed graph
It is similar to an adjacency matrix representation of a directed graph except that instead of using
the '1' for the existence of a path, here we have to use the weight associated with the edge. The
weights on the graph edges will be represented as the entries of the adjacency matrix. We can
understand it with the help of an example. Consider the below graph and its adjacency matrix
representation. In the representation, we can see that the weight associated with the edges is
represented as the entries in the adjacency matrix.
In the above image, we can see that the adjacency matrix representation of the weighted directed
graph is different from other representations. It is because, in this representation, the non-zero
values are replaced by the actual weight assigned to the edges.
Adjacency matrix is easier to implement and follow. An adjacency matrix can be used when the
graph is dense and a number of edges are large.
Though, it is advantageous to use an adjacency matrix, but it consumes more space. Even if the
graph is sparse, the matrix still consumes the same space.