Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Unit 4 Binary Tree

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 61

Unit 4

Binary Tree and Graphs

By : Prof Deepti Chaudhari-Bhirud


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 atmost 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.
Properties of Binary Tree
► The height of the tree is defined as the longest path from the root node to the leaf node. The tree
which is shown above has a height equal to 3. Therefore, the maximum number of nodes at height 3
is equal to (1+2+4+8) = 15.
► The minimum number of nodes possible at height h is equal to h+1.

Types of Binary Tree


There are four types of Binary tree:
► Full/ proper/ strict Binary tree
► Complete Binary tree
► Perfect Binary tree
► Degenerate Binary tree
► Balanced Binary tree
1. Full/ proper/ strict 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.
In this tree, we can observe that each node is either containing
zero or two children; therefore, it is a Full Binary tree.

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.
► 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 below tree is not a perfect binary tree because all the leaf nodes are not at the same level.
► Degenerate Binary Tree
► The degenerate binary tree is a tree in which all the internal nodes have only one children.
► Let's understand the Degenerate binary tree through examples.
► The beside tree is a degenerate binary tree because all the nodes
have only one child.
It is also known as a right-skewed tree as all the nodes have a right child only.
► Balanced Binary Tree
► The balanced binary tree is a tree in which both the left and right trees differ by atmost 1.
Binary tree implementation
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
{
int data,
struct node *left, *right;
}
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.
void main()
{
struct node *root;
root = create();
}
struct node *create()
{
struct node *temp;
int data;
temp = (struct node *)malloc(sizeof(struct node));
printf("Press 0 to exit");
printf("\n Press 1 for new node");
printf("Enter your choice : ");
scanf("%d", &choice);

if(choice==0)
{
return 0;
}
else
{
printf("Enter the data:");
scanf("%d", &data);
temp->data = data;
printf("Enter the left child of %d", data);
temp->left = create();
printf("Enter the right child of %d", data);
temp->right = create();
return temp;
}
}
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.
There are three types traversals used to visit a node:
► Inorder traversal
► Preorder traversal
► Postorder traversal
1. In-order Traversal
► In this traversal method, the left subtree is visited first, then the root and later the right sub-tree. We should always remember that every node may represent a subtree itself.
► If a binary tree is traversed in-order, the output will produce sorted key values in an ascending order.

► We start from A, and following in-order traversal, we move to its left subtree B. B is also traversed in-order. The process goes on until all the nodes are visited. The output of inorder
traversal of this tree will be −
► D→B→E→A→F→C→G
Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Visit root node.
Step 3 − Recursively traverse right subtree.
Pre-order Traversal
In this traversal method, the root node is visited first, then the left subtree and finally the right
subtree.
We start from A, and following pre-order traversal, we first visit A itself and then move to its left
subtree B. B is also traversed pre-order. The process goes on until all the nodes are visited. The
output of pre-order traversal of this tree will be −
A→B→D→E→C→F→G
Algorithm
Until all nodes are traversed −
Step 1 − Visit root node.
Step 2 − Recursively traverse left subtree.
Step 3 − Recursively traverse right subtree.
Post-order Traversal
In this traversal method, the root node is visited last, hence the name.
First we traverse the left subtree, then the right subtree and finally the root node.
► We start from A, and following Post-order traversal, we first visit the left subtree B. B is also traversed post-
order. The process goes on until all the nodes are visited. The output of post-order traversal of this tree will
be −
► D→E→B→F→G→C→A

Algorithm
Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Recursively traverse right subtree.
Step 3 − Visit root node.
void pre_order_traversal(struct node* root) {
if(root != NULL) {
printf("%d ",root->data);
pre_order_traversal(root->leftChild);
pre_order_traversal(root->rightChild);
}
}

void inorder_traversal(struct node* root) {


if(root != NULL) {
inorder_traversal(root->leftChild);
printf("%d ",root->data);
inorder_traversal(root->rightChild);
}
}

void post_order_traversal(struct node* root) {


if(root != NULL) {
post_order_traversal(root->leftChild);
post_order_traversal(root->rightChild);
printf("%d ", root->data);
}
}
►Binary Search Tree
❖ Binary Search tree can be defined as a class of binary trees, in which the nodes are arranged in a specific
order. This is also called ordered binary tree.
❖ In a binary search tree, the value of all the nodes in the left sub-tree is less than the value of the root.
❖ Similarly, value of all the nodes in the right sub-tree is greater than or equal to the value of the root.
❖ This rule will be recursively applied to all the left and right sub-trees of the root.
► Advantages of using binary search tree
1. Searching become very efficient in a binary search tree since, we get a hint at each step, about which sub-tree contains the
desired element.
2. The binary search tree is considered as efficient data structure in compare to arrays and linked lists. In searching process, it
removes half sub-tree at every step. Searching for an element in a binary search tree takes o(log 2n) time. In worst case, the
time it takes to search an element is 0(n).
3. It also speed up the insertion and deletion operations as compare to that in array and linked list.
► Create the binary search tree using the following data elements.
► 43, 10, 79, 90, 12, 54, 11, 9, 50
1. Insert 43 into the tree as the root of the tree.
2. Read the next element, if it is lesser than the root node element, insert it as the root of the left sub-tree.
3. Otherwise, insert it as the root of the right of the right sub-tree.
► The process of creating BST by using the given elements, is shown in the image below.
struct node{
int data;
struct node *left;
struct node *right;
};
struct node *root= NULL;

//createNode() will create a new node


struct node* createNode(int data){
//Create a new node
struct node *newNode = (struct node*)malloc(sizeof(struct node));
//Assign data to newNode, set left and right children to NULL
newNode->data= data;
newNode->left = NULL;
newNode->right = NULL;

return newNode;
void insert(int data) {
//Create a new node
struct node *newNode = createNode(data);

//Check whether tree is empty


if(root == NULL){
root = newNode;
return;
}
else {
//current node point to root of the tree
struct node *current = root, *parent = NULL;

while(true) {
//parent keep track of the parent node of current node.
parent = current;

//If data is less than current's data, node will be inserted to the left of tree
if(data < current->data) {
current = current->left;
if(current == NULL) {
parent->left = newNode;
return;
}
}
//If data is greater than current's data, node will be inserted to the right of tree
else {
current = current->right;
if(current == NULL) {
parent->right = newNode;
return;
}
}
}
}
struct node* deleteNode(struct node *node, int value) {
if(node == NULL){
return NULL;
}
else {
//value is less than node's data then, search the value in left subtree
if(value < node->data)
node->left = deleteNode(node->left, value);

//value is greater than node's data then, search the value in right subtree
else if(value > node->data)
node->right = deleteNode(node->right, value);

//If value is equal to node's data that is, we have found the node to be deleted
else {
//If node to be deleted has no child then, set the node to NULL
if(node->left == NULL && node->right == NULL)
node = NULL;

//If node to be deleted has only one right child


else if(node->left == NULL) {
node = node->right;
}

//If node to be deleted has only one left child


else if(node->right == NULL) {
node = node->left;
}

//If node to be deleted has two children node


else {
//then find the minimum node from right subtree
struct node *temp = minNode(node->right);
//Exchange the data between node and temp
node->data = temp->data;
//Delete the node duplicate node from right subtree
node->right = deleteNode(node->right, temp->data);
}
}
return node;
}
Searching node in BST

struct node* search(struct node *root, int x)


{
if(root==NULL || root->data==x) //if root->data is x then the element is found
return root;
else if(x>root->data) // x is greater, so we will search the right subtree
return search(root->right_child, x);
else //x is smaller than the data, so we will search the left subtree
return search(root->left_child,x);
}
What is threaded binary tree?

► Threaded binary tree is a simple binary tree but they have a specialty that null
pointers of leaf node of the binary tree is set to in order predecessor or in order
successor.
► The main idea behind setting such a structure is to make the in order and
preorder traversal of the tree faster without using any additional data
structure(e.g auxilary stack) or memory to do the traversal.
Types of Threaded Binary Tree

► There are two types of threaded binary tree:


1. Single Threaded Binary Tree
2. Double Threaded Binary Tree
3. Single Threaded Binary Tree: Here only the right NULL pointer are made to
point to in order successor.
4. Double Threaded Binary Tree: Here both the right as well as the left NULL
pointers are made to point in order successor and in order predecessor
respectively. (here the left threads are helpful in reverse in order traversal of the
tree )
Threaded Binary Tree
• Dangling pointers don’t have any predecessor or successor.
• Dangling can be solved as
 Introduce a header node.
 The left and right pointer of the header node are treated as normal links and are
initialized to point to header node itself.
Applications of Threaded Binary Tree

► The idea of threaded binary trees is to make inorder traversal of the binary tree
faster and do it without using any extra space, so sometimes in small systems
where hardware is very limited we use threaded binary tree for better efficiency
of the software in a limited hardware space.
Balanced Trees- AVL Tree
Balanced binary tree
● The disadvantage of a binary search tree is that its height can be as large as N-1
● This means that the time needed to perform insertion and deletion and many
other operations can be O(N) in the worst case
● We want a tree with small height
● A binary tree with N node has height at least (log N)
● Thus, our goal is to keep the height of a binary search tree O(log N)
● Such trees are called balanced binary search trees. Examples are AVL tree, red-
black tree.
Binary Search Tree - Best Time
● All BST operations are O(h), where d is tree depth
● minimum d is for a binary tree with N nodes
■ What is the best case tree?
■ What is the worst case tree?
● So, best case running time of BST operations is O(log N) 2h log N
Binary Search Tree - Worst Time

● Worst case running time is O(N)


■ What happens when you Insert elements in ascending order?
○ Insert: 2, 4, 6, 8, 10, 12 into an empty BST
■ Problem: Lack of “balance”:
○ compare depths of left and right subtree
■ Unbalanced degenerate tree
AVL Tree Generation
AVL Tree Rotations

LL Rotation

In LL imbalance – rotate tree from root node to right


RR , RL and LR Rotation
In RR rotation – rotate tree from root to left
In RL rotation – rotate tree from second child to right and then perform RR rotation
In LR rotation – rotate tree from second child to left and then perform LL rotation
Operations using HEAP
GRAPHS
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.
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 figure.
Directed Graph :
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
V0=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 neighbors or adjacent nodes.

► Degree of the Node - 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.
Linked Representation

► In the linked representation, an adjacency list is used to store the Graph into the computer's memory.
► Consider the undirected graph shown in the following figure and check the adjacency list representation.

An adjacency list is maintained for each node present in the graph which stores the node value and a
pointer to the next adjacent node to the respective node. If all the adjacent nodes are traversed then store
the NULL in the pointer field of last node of the list. The sum of the lengths of adjacency lists is equal to the
twice of the number of edges present in an undirected graph.
Graph Traversal Algorithm
Traversing the graph means examining all the nodes and vertices of the graph. There are two standard
methods by using which, we can traverse the graphs. Lets discuss each one of them in detail.
► Breadth First Search
► Depth First Search

Breadth First Search (BFS) Algorithm


Breadth first search is a graph traversal algorithm that starts traversing the graph from root node and
explores all the neighbouring nodes. Then, it selects the nearest node and explore all the unexplored nodes.
The algorithm follows the same process for each of the nearest node until it finds the goal.
It uses Queue data structure for node visit.
Bfs demo-
Depth First Search (DFS) Algorithm
Depth first search (DFS) algorithm starts with the initial node of the graph G, and then goes to deeper and
deeper until we find the goal node or the node which has no children. The algorithm, then backtracks from the
dead end towards the most recent node that is yet to be completely unexplored.
The data structure which is being used in DFS is stack. The process is similar to BFS algorithm. In DFS, the
edges that leads to an unvisited node are called discovery edges while the edges that leads to an already
visited node are called block edges.
Algorithm
Step 1: SET STATUS = 1 (ready state) for each node in G
Step 2: Push the starting node A on the stack and set its STATUS = 2 (waiting state)
Step 3: Repeat Steps 4 and 5 until STACK is empty
Step 4: Pop the top node N. Process it and set its STATUS = 3 (processed state)
Step 5: Push on the stack all the neighbours of N that are in the ready state (whose STATUS = 1) and set their
STATUS = 2 (waiting state)
[END OF LOOP]
Step 6: EXIT
Consider the following graph Stack : B

Push H onto the stack Pop the top of the stack i.e. B and push all the neighbours

STACK : H
POP the top element of the stack i.e. H, print it and push all Print B
the neighbours of H onto the stack that are is ready state. Stack : C
Print H Pop the top of the stack i.e. C and push all the neighbours.
STACK : A Print C
Pop the top element of the stack i.e. A, print it and push all the Stack : E, G
neighbours of A onto the stack that are in ready state.
Pop the top of the stack i.e. G and push all its neighbours.
Print A
Print G
Stack : B, D
Stack : E
Pop the top element of the stack i.e. D, print it and push all the
neighbours of D onto the stack that are in ready state. Pop the top of the stack i.e. E and push all its neighbours.

Print D Print E

Stack : B, F Stack :

Pop the top element of the stack i.e. F, print it and push all the Hence, the stack now becomes empty and all the nodes of the
neighbours of F onto the stack that are in ready state. graph have been traversed.
The printing sequence of the graph will be :

Print F H→A→D→F→B→C→G→E
Warshall Algorithm
Floyd-Warshall Algorithm is an algorithm for finding the shortest path between all the pairs of vertices in a
weighted graph. This algorithm works for both the directed and undirected weighted graphs.
Follow the steps below to find the shortest path between all the pairs of vertices.
1. Create a matrix A0 of dimension n*n where n is the number of vertices. The row and the column are
indexed as i and j respectively. i and j are the vertices of the graph.
2. Each cell A[i][j] is filled with the distance from the i th vertex to the jth vertex. If there is no path from ith
vertex to jth vertex, the cell is left as infinity.
Now, create a matrix A1 using matrix A0. The elements in the first column and the first row are left as they
are. The remaining cells are filled in the following way.
Let k be the intermediate vertex in the shortest path from source to destination. In this step, k is the first
vertex. A[i][j] is filled with (A[i][k] + A[k][j]) if (A[i][j] > A[i][k] + A[k][j]).
That is, if the direct distance from the source to the destination is greater than the path through the
vertex k, then the cell is filled with A[i][k] + A[k][j].
In this step, k is vertex 1. We calculate the distance from source vertex to destination vertex through this
vertex k.
► or example: For A1[2, 4], the direct distance from vertex 2 to 4 is 4 and the sum of the distance from
vertex 2 to 4 through vertex (ie. from vertex 2 to 1 and from vertex 1 to 4) is 7. Since 4 < 7, A0[2, 4] is
filled with 4.
► Similarly, A2 is created using A1. The elements in the second column and the second row are left as they
are.

In this step, k is the second vertex (i.e. vertex 2). The remaining steps are the same as in step 2.

Similarly, A3 and A is also created


4
A4 gives the shortest path between each pair of vertices.

You might also like