![]() |
![]() |
![]() |
![]() |
TREES 3.1 PRELIMINARIES : TREE : A tree is a finite set of one or more nodes such that there is a specially designated node called the Root, and zero or more non empty sub trees T1, T2....Tk, each of whose roots are connected by a directed edge from Root R.
Fig. 3.1.1 Tree ROOT : A node which doesn't have a parent. In the above tree. The Root is A. NODE : Item of Information. LEAF : A node which doesn't have children is called leaf or Terminal node. Here B, K, L, G, H, M, J are leafs. SIBLINGS : Children of the same parents are said to be siblings, Here B, C, D, E are siblings, F, G are siblings. Similarly I, J & K, L are siblings. PATH : A path from node n, to nk is defined as a sequence of nodes n1, n2,n3....nk such that ni is the parent of
ni+1. for node to root. In fig 3.1.1 path from A to L is A, C, F, L. where A is the parent for C, C is the parent of F and F is the parent of L. LENGTH : The length is defined as the number of edges on the path. In fig 3.1.1 the length for the path A to L is 3. DEGREE : The number of subtrees of a node is called its degree.
| |||
3
| |||
| |||
Data Structures 3.1 | |||
![]() |
![]() |
![]() |
In fig 3.1.1 Degree of A is 4 Degree of C is 2 Degree of D is 1 Degree of H is 0. * The degree of the tree is the maximum degree of any node in the tree. In fig 3.1.1 the degree of the tree is 4. LEVEL : The level of a node is defined by initially letting the root be at level one, if a node is at level L then its children are at level L + 1. Level of A is 1. Level of B, C, D, is 2. Level of F, G, H, I, J is 3 Level of K, L, M is 4. DEPTH : For any node n, the depth of n is the length of the unique path from root to n. The depth of the root is zero. In fig 3.1.1 Depth of node F is 2. Depth of node L is 3. HEIGHT : For any node n, the height of the node n is the length of the longest path from n to the leaf. The height of the leaf is zero In fig 3.1.1 Height of node F is 1. Height of L is 0. Note : The height of the tree is equal to the height of the root Depth of the tree is equal to the height of the tree. 3.2 BINARY TREE Definition :- Binary Tree is a tree in which no node can have more than two children. Maximum number of nodes at level i of a binary tree is 2i-1. | ||
| ||
Data Structures 3.2 | ||
![]() |
![]() |
![]() |
Fig. 3.2.1 Binary Tree
BINARY TREE NODE DECLARATIONS Struct TreeNode { int Element; Struct TreeNode *Left ; Struct TreeNode *Right; }; COMPARISON BETWEEN GENERAL TREE & BINARY TREE General Tree Binary Tree * General Tree has any * A Binary Tree has not number of children. more than two children.
FULL BINARY TREE :- A full binary tree of height h has
2h+1 - 1 nodes.
| ||
| ||
Data Structures 3.3 | ||
![]() |
![]() |
![]() |
Here height is 3 binary tree is = 23+1 -1 = 15 nodes.
Fig. 3.2.2 A Full Binary Tree COMPLETE BINARY TREE : A complete binary tree of height h has between 2h and 2h+1 - 1 nodes. In the bottom level the elements should be filled from left to right.
Fig. 3.2.3 A Complete Binary Tree.
Note : A full binary tree can be a complete binary tree, but all complete binary tree is not a full binary tree.
| ||
| ||
Data Structures 3.4 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
3.2.1REPRESENTATION OF A BINARY TREE There are two ways for representing binary tree, they are * Linear Representation * Linked Representation Linear Representation The elements are represented using arrays. For any element in position i, the left child is in position 2i, the right child is in position (2i + 1), and the parent is in position (i/2).
Fig. 3.2.4 Linear Representation Linked Representation The elements are represented using pointers. Each node in linked representation has three fields, namely, * Pointer to the left subtree * Data field * Pointer to the right subtree In leaf nodes, both the pointer fields are assigned as NULL.
| ||||
| ||||
Data Structures 3.5 | ||||
|
![]() |
![]() |
![]() |
Fig. 3.2.5 Linked Representation 3.2.2 EXPRESSION TREE Expression Tree is a binary tree in which the leaf nodes are operands and the interior nodes are operators. Like binary tree, expression tree can also be travesed by inorder, preorder and postorder traversal. Constructing an Expression Tree Let us consider postfix expression given as an input for constructing an expression tree by performing the following steps : 1. Read one symbol at a time from the postfix expression. 2. Check whether the symbol is an operand or operator. (a) If the symbol is an operand, create a one - node tree and push a pointer on to the stack. (b) If the symbol is an operator pop two pointers from the stack namely T1 and T2 and form a new tree with root as the operator and T2 as a left child and T1 as a right child. A pointer to this new tree is then pushed onto the stack. Example : - ab + c * The first two symbols are operand, so create a one node tree and push the pointer on to the stack.
Fig. 3.2.6 (a)
| ||
| ||
Data Structures 3.6 | ||
![]() |
![]() |
![]() |
Next `+' symbol is read, so two pointers are popped, a new tree is formed and a pointer to this is pushed on to the stack.
Fig. 3.2.6 (b) Next the operand C is read, so a one node tree is created and the pointer to it is pushed onto the stack.
Fig. 3.2.6 (c) Now `*' is read, so two trees are merged and the pointer to the final tree is pushed onto the stack.
Fig. 3.2.6 (d)
| ||
| ||
Data Structures 3.7 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
3.3 The Search Tree ADT : - Binary Search Tree Definition : - Binary search tree is a binary tree in which for every node X in the tree, the values of all the keys in its left subtree are smaller than the key value in X, and the values of all the keys in its right subtree are larger than the key value in X.
Fig. 3.3.1 Binary Search Tree Comparision Between Binary Tree & Binary Search Tree Binary Tree Binary Search Tree * A tree is said to be a binary * A binary search tree is a binary tree in which tree if it has atmost two childrens. the key values in the left node is less than the root and the keyvalues in the right node is greater than the root. * It doesn't have any order. * Example
| ||||||
|
| |||||
| ||||||
Data Structures 3.8 | ||||||
![]() |
![]() |
![]() |
Note : * Every binary search tree is a binary tree. * All binary trees need not be a binary search tree. DECLARATION ROUTINE FOR BINARY SEARCH TREE Struct TreeNode; typedef struct TreeNode * SearchTree; SearchTree Insert (int X, SearchTree T); SearchTree Delete (int X, SearchTree T); int Find (int X, SearchTree T); int FindMin (Search Tree T); int FindMax (SearchTree T); SearchTree MakeEmpty (SearchTree T); Struct TreeNode { int Element ; SearchTree Left; SearchTree Right; }; Make Empty :- This operation is mainly for initialization when the programmer prefer to initialize the first element as a one - node tree. ROUTINE TO MAKE AN EMPTY TREE :- SearchTree MakeEmpty (SearchTree T) { if (T! = NULL) { MakeEmpty (T MakeEmpty (T free (T); } return NULL ; } | ||
| ||
Data Structures 3.9 | ||
![]() |
![]() |
![]() |
Insert : - To insert the element X into the tree, * Check with the root node T * If it is less than the root, Traverse the left subtree recursively until it reaches the T T * If X is greater than the root. Traverse the right subtree recursively until it reaches the T T ROUTINE TO INSERT INTO A BINARY SEARCH TREE SearchTree Insert (int X, searchTree T) { if (T = = NULL) { T = malloc (size of (Struct TreeNode)); if (T! = NULL) // First element is placed in the root. { T T T } } else if (X < T T else if (X > T T // Else X is in the tree already. return T; } | ||
| ||
Data Structures 3.10 | ||
![]() |
![]() |
![]() |
Example : - To insert 8, 5, 10, 15, 20, 18, 3 * First element 8 is considered as Root.
As 5 < 8, Traverse towards left
10 > 8, Traverse towards Right.
Similarly the rest of the elements are traversed.
After 20 After 18
| ||
| ||
| ||
Data Structures 3.11 | ||
![]() |
![]() |
![]() |
Find : - * Check whether the root is NULL if so then return NULL. * Otherwise, Check the value X with the root node value (i.e. T (1) If X is equal to T (2) If X is less than T (3) If X is greater than T ROUTINE FOR FIND OPERATION Int Find (int X, SearchTree T) { If T = = NULL) Return NULL ; If (X < T return Find (X, T else If (X > T return Find (X, T else return T; // returns the position of the search element. } Example : - To Find an element 10 (consider, X = 10)
10 is checked with the Root 10 > 8, Go to the right child of 8 | ||
| ||
Data Structures 3.12 | ||
![]() |
![]() |
![]() |
10 is checked with Root 15 10 < 15, Go to the left child of 15.
10 is checked with root 10 (Found)
Find Min : This operation returns the position of the smallest element in the tree. To perform FindMin, start at the root and go left as long as there is a left child. The stopping point is the smallest element. RECURISVE ROUTINE FOR FINDMIN int FindMin (SearchTree T) { if (T = = NULL); return NULL ; else if (T return T; else return FindMin (T }
| ||
| ||
Data Structures 3.13 | ||
![]() |
![]() |
![]() |
Example : - Root T
T
(a) T! = NULL and T Traverse left Traverse left
Min T (c) Since T NON - RECURSIVE ROUTINE FOR FINDMIN int FindMin (SearchTree T) { if (T! = NULL) while (T T = T return T; } FindMax FindMax routine return the position of largest elements in the tree. To perform a FindMax, start at the root and go right as long as there is a right child. The stopping point is the largest element. | ||
| ||
Data Structures 3.14 | ||
![]() |
![]() |
![]() |
RECURSIVE ROUTINE FOR FINDMAX int FindMax (SearchTree T) { if (T = = NULL) return NULL ; else if (T return T; else FindMax (T } Example :- Root T
(a) T! = NULL and T Traverse Right Traverse Right
Max
(c) Since T | ||
| ||
Data Structures 3.15 | ||
![]() |
![]() |
![]() |
NON - RECURSIVE ROUTINE FOR FINDMAX int FindMax (SearchTree T) { if (T! = NULL) while (T T = T return T ; } Delete : Deletion operation is the complex operation in the Binary search tree. To delete an element, consider the following three possibilities. CASE 1 CASE 2 CASE 3 CASE 1 If the node is a leaf node, it can be deleted immediately. Delete : 8
After the deletion
CASE 2 : - Node with one child If the node has one child, it can be deleted by adjusting its parent pointer that points to its child node. | ||
| ||
Data Structures 3.16 | ||
![]() |
![]() |
![]() |
To Delete 5
before deletion After deletion To delete 5, the pointer currently pointing the node 5 is now made to to its child node 6. Case 3 : Node with two children It is difficult to delete a node which has two children. The general strategy is to replace the data of the node to be deleted with its smallest data of the right subtree and recursively delete that node. Example 1 : To Delete 5 :
* The minimum element at the right subtree is 7.
(a)
| ||
| ||
Data Structures 3.17 | ||
![]() |
![]() |
![]() |
* Now the value 7 is replaced in the position of 5.
* Since the position of 7 is the leaf node delete immediately.
(b)
After deleting the node 5
(c)
Example 2 : - To Delete 25
* The minimum element at the right subtree of 25 is 30
(a)
| ||
| ||
Data Structures 3.18 | ||
![]() |
![]() |
![]() |
* The minimum value 30 is replaced in the position of 25
(b)
* Since this node has one child, the pointer currently pointing to this node is made to points to its child node 32.
(c)
| ||
| ||
Data Structures 3.19 | ||
![]() |
![]() |
![]() |
Binary Search Tree after deleting 25
(d) DELETION ROUTINE FOR BINARY SEARCH TREES SearchTree Delete (int X, searchTree T) { int Tmpcell ; if (T = = NULL) Error ("Element not found"); else if (X < T T else if (X > T T // Found Element tobe deleted else // Two children if (T { // Replace with smallest data in right subtree Tmpcell = FindMin (T T T } | ||
| ||
Data Structures 3.20 | ||
![]() |
![]() |
![]() |
| ||
else // one or zero children { Tmpcell = T; if (T T = T else if (T T = T free (TmpCell); } return T; } 3.4 AVL Tree : - (Adelson - Velskill and LANDIS) An AVL tree is a binary search tree except that for every node in the tree, the height of the left and right subtrees can differ by atmost 1. The height of the empty tree is defined to be - 1. A balance factor is the height of the left subtree minus height of the right subtree. For an AVL tree all balance factor should be +1, 0, or -1. If the balance factor of any node in an AVL tree becomes less than -1 or greater than 1, the tree has to be balanced by making either single or double rotations. BF = 1
BF = 0 (a)
(b) | ||
| ||
Data Structures 3.21 |
![]() |
![]() |
![]() |
![]() |
![]() |
(c) Fig. 3.4.1 AVL Tree An AVL tree causes imbalance, when any one of the following conditions occur. Case 1 : An insertion into the left subtree of the left child of node Case 2 : An insertion into the right subtree of the left child of node Case 3 : An insertion into the left subtree of the right child of node Case 4 : An insertion into the right subtree of the right child of node These imbalances can be overcome by 1. Single Rotation 2. Double Rotation. Single Rotation Single Rotation is performed to fix case 1 and case 4. Case 1. An insertion into the left subtree of the left child of K2. Single Rotation to fix Case 1. General Representation
Fig. 3.4.2 (a) Before rotation
| ||||
| ||||
Data Structures 3.22 | ||||
![]() |
![]() |
![]() |
Fig. 3.4.2 (b) After rotation
ROUTINE TO PERFORM SINGLE ROTATION WITH LEFT SingleRotatewithLeft (Position K2) { Position K1; K1 =
K2 K2 K1 K2 K1 return K1 ; }
| ||
| ||
Data Structures 3.23 | ||
![]() |
![]() |
![]() |
Example : Inserting the value `1' in the following AVL Tree makes AVL Tree imbalance
Before
After Fig. 3.4.3
BF = 0
| ||
| ||
Data Structures 3.24 | ||
![]() |
![]() |
![]() |
Single Rotation to fix Case 4 :- Case 4 : - An insertion into the right subtree of the right child of K1. General Representation
Fig. 3.4.4 (a) Before rotation
Fig. 3.4.4 (b) After Rotation ROUTINE TO PERFORM SINGLE ROTATION WITH RIGHT :- Single Rotation With Right (Position K2) { Position K2 ; K2 =
K1 K1 K2 | ||
| ||
Data Structures 3.25 | ||
![]() |
![]() |
![]() |
K2 K1 Return K2 ; } example : - inserting the value `10' in the following AVL Tree.
Fig. 3.45 (a) AVL Tree with Imbalance
Fig. 3.4.5 (b) Balanced AVL Tree rotate with right | ||
| ||
Data Structures 3.26 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
Double Rotation Double Rotation is performed to fix case 2 and case 3. Case 2 : An insertion into the right subtree of the left child. General Representation
Before After Fig. 3.4.6 This can be performed by 2 single rotations.
Single Rotation with right
(K3 double rotation | ||||||||
| ||||||||
Data Structures 3.27 | ||||||||
![]() |
![]() |
![]() |
Single Rotation with left (K3)
Fig. 3.4.7 Balanced AVL Tree
ROUTINE TO PERFORM DOUBLE ROTATION WITH LEFT : Double Rotate with left (Position K3) { /* Rotation Between K1 & K2 */ K3 /* Rotation Between K3 & K2 */ Return Single Rotate With Left (K3); } | ||
| ||
Data Structures 3.28 | ||
![]() |
![]() |
![]() |
![]() |
Example : Insertion of either `12' or `18' makes AVL Tree imbalance
(a) before rotation
double rotation
(b) After rotation This can be done by performing single rotation with right of `10' & then perform the single
rotation with left of 20 as shown below.
| |||
| |||
Data Structures 3.29 | |||
![]() |
![]() |
![]() |
![]() |
rotate with right
rotate with left
Fig. 3.4.7 Balanced AVL Tree
| |||
| |||
Data Structures 3.30 | |||
![]() |
![]() |
![]() |
Case 4 : An Insertion into the left subtree of the right child of K1. General Representation :-
double rotation
Fig. 3.4.8 This can also be done by performing single rotation with left and then single rotation with right.
| ||
| ||
Data Structures 3.31 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|
| |||||||||
| |||||||||
Single Rotate with Left (K3) | |||||||||
|
Single Rotate with Right (K1)
Fig. 3.4.9 Balanced AVL Tree After double rotation.
| ||||||||
| |||||||||
| |||||||||
Data Structures 3.32 | |||||||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
ROUTINE TO PERFORM DOUBLE ROTATION WITH RIGHT : Double Rotate with Right (Position K1) { /* Rotation Between K2 & K3 */ K1 /* Rotation Between K1 & K2 */ return Single Rotate With Right (K1); } Example : | ||||||||||||||
| ||||||||||||||
(a) before | ||||||||||||||
double rotate | ||||||||||||||
(b) After | ||||||||||||||
| ||||||||||||||
Data Structures 3.33 | ||||||||||||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
This can be done by performing single rotation with left of `15' and then performing the single rotation with right of `10' as shown below. | ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
single rotate with left | ||||||||||||||||
| ||||||||||||||||
|
single rotate with right | |||||||||||||||
| ||||||||||||||||
Fig. 3.4.9 BALANCE AVL Tree | ||||||||||||||||
| ||||||||||||||||
Data Structures 3.34 | ||||||||||||||||
![]() |
![]() |
![]() |
ROUTINE TO INSERT IN AN AVL TREE : - AVLTree Insert (AVL tree T, int X) { if (T = = NULL) { T = malloc (size of (Struct AVLnode)); if (T = = NULL) Error ("out of space"); else { T T T T } } else if (X < T { T if (Height (T if (X < T T = Single Rotate With left (T); else T = Double Rotate is the left (T); } else if (X > T { T | ||
| ||
Data Structures 3.35 | ||
![]() |
![]() |
![]() |
if (Height (T if(X > T T = Single Rotate with Right (T); else T = Double Rotate with Right (T); } T return T; } Example : Let us consider how to balance a tree while inserting the numbers from 1 to 10. Insert the value 1. 1 BF = 0 Insert the value 2
Balanced Tree Insert the value 3
Imbalanced Tree Balanced Tree Here the tree imbalances at the node 1. so the single rotation with left is performed. | ||
| ||
Data Structures 3.36 | ||
![]() |
![]() |
![]() |
Insert the value 4
Balanced AVL Tree
Insert the value 5
Imbalanced Tree
Balanced Tree Tree is imbalanced at node `3', perform the single rotation with left to balance it.
BF = 0 BF = 0 | ||
| ||
Data Structures 3.37 | ||
![]() |
![]() |
![]() |
|
Insert the value 6
Imbalanced Tree
Balanced Tree
Insert the value 7
Imbalanced Tree
BF = -1 BF = 0 BF = 0 BF = 0 | |||
|
Data Structures 3.38 | ||
![]() |
![]() |
![]() |
Balanced Tree
Insert the value 8
Balanced Tree
| ||
| ||
Data Structures 3.39 | ||
![]() |
![]() |
![]() |
insert the value 9
Imbalanced Tree
Balanced Tree
BF = -2
| ||
| ||
Data Structures 3.40 | ||
![]() |
![]() |
![]() |
Insert the value 10
Imbalanced Tree
Balanced Tree
| ||
| ||
Data Structures 3.41 | ||
![]() |
![]() |
![]() |
3.5 Tree Traversals Traversing means visiting each node only once. Tree traversal is a method for visiting all the nodes in the tree exactly once. There are three types of tree traversal techniques, namely 1. Inorder Traversal 2. Preorder Traversal 3. Postorder Traversal Inorder Traversal The inorder traversal of a binary tree is performed as * Traverse the left subtree in inorder * Visit the root * Traverse the right subtree in inorder. Example :
Fig. 3.5.1 Inorder 10, 20, 30
Fig. 3.5.2 A B C D E G H I J K
| ||
| ||
Data Structures 3.42 | ||
![]() |
![]() |
![]() |
The inorder traversal of the binary tree for an arithmetic expression gives the expression in an infix form. RECURSIVE ROUTINE FOR INORDER TRAVERSAL void Inorder (Tree T) { if (T ! = NULL) { Inorder (T printElement (T Inorder (T } } Preorder Traversal The preorder traversal of a binary tree is performed as follows, * Visit the root * Traverse the left subtree in preorder * Traverse the right subtree in preorder. Example 1 :
Fig. 3.5.3 Preorder : 20, 10, 30 | ||
| ||
Data Structures 3.43 | ||
![]() |
![]() |
![]() |
Example 2 :
Fig. 3.5.4 Preorder D C A B I G E H K J the preorder traversal of the binary tree for the given expression gives in prefix form. RECURSIVE ROUTINE FOR PREORDER TRAVERSAL void Preorder (Tree T) { if (T ! = NULL) { printElement (T Preorder (T Preorder (T }
Postorder Traversal The postorder traversal of a binary tree is performed by the following steps. * Traverse the left subtree in postorder. * Traverse the right subtree in postorder. * Visit the root. | ||
| ||
Data Structures 3.44 | ||
![]() |
![]() |
![]() |
Example : 1
Fig. 3.5.5 Postorder : - 10, 30, 20 Example : 2
Fig. 3.5.6 Post order : - B A C E H G J K I D The postorder traversal of the binary tree for the given expression gives in postfix form. RECURSIVE ROUTINE FOR POSTORDER TRAVERSAL void Postorder (Tree T) { if (T ! = NULL) { Postorder (T Postorder (T PrintElement (T }
| ||
| ||
Data Structures 3.45 | ||
![]() |
![]() |
![]() |
Example : - Traverse the given tree using inorder, preorder and postorder traversals.
(1)
Fig. 3.5.7 Inorder : A + B * C - D / E Preorder : * + A B - C / D E Postorder : A B + C D E / - *
Fig. 3.5.8
Inorder : 5 10 15 20 25 30 40 Preorder : 20 10 5 15 30 25 40 Postorder : 5 15 10 25 40 30 20
| ||
| ||
Data Structures 3.46 | ||
![]() |
![]() |
![]() |
3.6 Hashing Hash Table The hash table data structure is an array of some fixed size, containing the keys. A key is a value associated with each record.
Fig. 3.6.1 Hash Table Hashing Function A hashing function is a key - to - address transformation, which acts upon a given key to compute the relative position of the key in an array. A simple Hash function HASH (KEYVALUE) = KEYVALUE MOD TABLESIZE Example : - Hash (92) Hash (92) = 92 mod 10 = 2 The keyvalue `92' is placed in the relative location `2'. ROUTINE FOR SIMPLE HASH FUNCTION Hash (Char *key, int Table Size) { int Hashvalue = 0; while (* key ! = `\0') Hashval + = * key ++; return Hashval % Tablesize; }
| ||
| ||
Data Structures 3.47 | ||
![]() |
![]() |
![]() |
Some of the Methods of Hashing Function 1. Module Division 2. Mid - Square Method 3. Folding Method 4. PSEUDO Random Method 5. Digit or Character Extraction Method 6. Radix Transformation. Collisions Collision occurs when a hash value of a record being inserted hashes to an address (i.e. Relative position) that already contain a different record. (ie) When two key values hash to the same position. Collision Resolution The process of finding another position for the collide record. Some of the Collision Resolution Techniques 1. Seperate Chaining 2. Open Addressing 3. Multiple Hashing Seperate Chaining Seperate chaining is an open hashing technique. A pointer field is added to each record location. When an overflow occurs this pointer is set to point to overflow blocks making a linked list. In this method, the table can never overflow, since the linked list are only extended upon the arrival of new keys. | ||
| ||
Data Structures 3.48 | ||
![]() |
![]() |
![]() |
Insert : 10, 11, 81, 10, 7, 34, 94, 17
Fig. 3.6.2 Insertion To perform the insertion of an element, traverse down the appropriate list to check whether the element is already in place. If the element turns to be a new one, it is insertd either at the front of the list or at the end of the list. If it is a duplicate element, an extra field is kept and placed. INSERT 10 : Hash (k) = k% Tablesize Hash (10) = 10 % 10 Hash (10) = 0
| ||
| ||
Data Structures 3.49 | ||
![]() |
![]() |
![]() |
INSERT 11 : Hash (11) = 11 % 10 Hash (11) = 1 INSERT 81 : Hash (81) = 81% 10 Hash (81) = 1 The element 81 collides to the same hash value 1. To place the value 81 at this position perform the following. Traverse the list to check whether it is already present. Since it is not already present, insert at end of the list. Similarly the rest of the elements are inserted. ROUTINE TO PERFORM INSERTION void Insert (int key, Hashtable H) { Position Pos, Newcell; List L; /* Traverse the list to check whether the key is already present */ Pos = FIND (Key, H); If (Pos = = NULL) /* Key is not found */ { Newcell = malloc (size of (struct ListNode)); If (Newcell ! = NULL) ( L = H Newcell Newcell /* Insert the key at the front of the list */ L } } } | ||
| ||
Data Structures 3.50 | ||
![]() |
![]() |
![]() |
FIND ROUTINE Position Find (int key, Hashtable H) { Position P; List L; L = H P = L while (P! = NULL && P P = p return p; } Advantage More number of elements can be inserted as it uses array of linked lists. Disadvantage of Seperate Chaining * It requires pointers, which occupies more memory space. * It takes more effort to perform a search, since it takes time to evaluate the hash function and also to traverse the list. OPEN ADDRESSING Open addressing is also called closed Hashing, which is an alternative to resolve the collisions with linked lists. In this hashing system, if a collision occurs, alternative cells are tried until an empty cell is found. (ie) cells h0(x), h1(x), h2(x).....are tried in succession. There are three common collision resolution strategies. They are (i) Linear Probing (ii) Quadratic probing (iii) Double Hashing. LINEAR PROBING In linear probing, for the ith probe the position to be tried is (h(k) + i) mod tablesize, where F(i) = i, is the linear function. In linear probing, the position in which a key can be stored is found by sequentially searching all position starting from the position calculated by the hash function until an empty cell is found. If the end of the table is reached and no empty cells has been found, then the search is continued from the beginning of the table. It has a tendency to create clusters in the table. | ||
| ||
Data Structures 3.51 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
INSERT : 42, 39, 69, 21, 71, 55, 33 EMPTY After After After After After After After TABLE 42 39 69 21 71 55 33 0 69 69 69 69 69 1 21 21 21 21 2 42 42 42 42 42 42 42 3 71 71 71 4 33 5 55 55 6 7 8 9 39 39 39 39 39 39 | ||||
| ||||
Data Structures 3.52 | ||||
![]() |
![]() |
![]() |
In fig 3.6.3 first collision occurs when 69 is inserted, which is placed in the next available spot namely spot 0, which is open. The next collision occurs when 71 is inserted, which is placed in the next available spot namely spot 3. The collision for 33 is handled in a similar manner. Advantage : * It doesn't requires pointers Disadvantage * It forms clusters, which degrades the performance of the hash table for storing and retrieving data. 3.7 PRIORITY QUEUES 3.7.1 Need for Priority Queue In multiuser environment, the operating system scheduler must decide which of several processes to run. Generally a process is allowed to run only for a fixed period of time. If an algorithm uses simple queue, jobs are initially placed at the end of the queue. The scheduler will take the first job on the queue and allow it to run until either it finishes or its timelimit is up. If it is not completed the alloted time, then place it at the end of the queue. This is not appropriate, because very short jobs will take a long time because of the wait involved to run. It can be overcome by using priority queues in which short jobs are assigned a higher precedence. Futhermore, some jobs that are not short are still very important and should also have preferences. 3.7.2 Model A priority queue is a special kind of queue data structure which will have precedence over jobs. Basic operations performed by priority queue are : Insert Operation DeleteMin Operation Insert operation is similar to Enqueue, where we insert an element in the priority queue. Deletemin operation is equivalent of queue's Dequeue operations, where we delete at minimum element from the priority queue.
Fig. 3.7.1 Basic Model of a priority Queue
| ||
| ||
Data Structures 3.53 | ||
![]() |
![]() |
![]() |
3.7.3 Simple Implementation There are several ways for implementing priority queue. 1. Linked list 2. Binary search tree 3. Binary heap Linked List A simple linked list implementation of priority queue requires O(1) time to perform the insertion at the front and O(N) time to delete the minimum element. Binary Search Tree This implementation gives an average running time of O(logN) for both insertion and deletemin operations. Deletemin operation makes tree imbalance, by making the right subtree heavy as we are repeatedly removing the node from the left subtree. 3.7.4 BINARY HEAP The efficient way of implementing priority queue is Binary Heap. Binary heap is merely referred as Heaps, Heap have two properties namely * Structure property * Heap order property. Like AVL trees, an operation on a heap can destroy one of the properties, so a heap operation must not terminate until all heap properties are in order. Both the operations require the average running time as O(log N). Structure Property A heap should be complete binary tree, which is a completely filled binary tree with the possible exception of the bottom level, which is filled from left to right. A complete binary tree of height H has between 2H and 2H+1 -1 nodes. For example if the height is 3. Then the numer of nodes will be between 8 and 15. (ie) (23 and 24-1). For any element in array position i, the left child is in position 2i, the right child is in position 2i + 1, and the parent is in i/2. As it is represented as array it doesn't require pointers and also the operations required to traverse the tree are extremely simple and fast. But the only disadvantage is to specify the maximum heap size in advance. | ||
| ||
Data Structures 3.54 | ||
![]() |
![]() |
![]() |
Fig. 3.7.2 A Complete Binary Tree
Fig. 3.7.3 Array implementation of complete binary tree
Fig. 3.7.4 Not a Complete Binary Tree Heap Order Property In a heap, for every node X, the key in the parent of X is smaller than (or equal to) the key in X, with the exception of the root (which has no parent). This property allows the deletemin operations to be performed quickly has the minimum
element can always be found at the root. Thus, we get the FindMin operation in constant time.
| ||
| ||
Data Structures 3.55 | ||
![]() |
![]() |
![]() |
Fig. 3.7.5 (a) Binary tree with Fig. 3.7.5 (b) Binary tree with structure and heap structure but violtating heap order property. heap order property Declaration for priority queue Struct Heapstruct; typedef struct Heapstruct * priority queue; PriorityQueue Initialize (int MaxElements); void insert (int X, PriorityQueue H); int DeleteMin (PriorityQueue H); Struct Heapstruct { int capacity; int size; int *Elements; }; Initialization PriorityQueue Initialize (int MaxElements) { PriorityQueue H; H = malloc (sizeof (Struct Heapstruct)); H H H return H; }
| ||
| ||
Data Structures 3.56 | ||
![]() |
![]() |
![]() |
3.6.4.3 BASIC HEAP OPERATIONS To perform the insert and DeleteMin operations ensure that the heap order property is maintained. Insert Operation To insert an element X into the heap, we create a hole in the next available location, otherwise the tree will not be complete. If X can be placed in the hole without violating heap order, then place the element X there itself. Otherewise, we slide the element that is in the hole's parent node into the hole, thus bubbling the hole up toward the root. This process continues until X can be placed in the hole. This general strategy is known as Percolate up, in which the new element is percolated up the heap until the correct location is found. Routine To Insert Into A Binary Heap void insert (int X, PriorityQueue H) { int i; If (Isfull (H)) { Error (" priority queue is full"); return; } for (i = ++H /* If the parent value is greater than X, then place the element of parent node into the hole */. H H } | ||
| ||
Data Structures 3.57 | ||
![]() |
![]() |
![]() |
Example : To Insert 10 :
Fig. 3.7.6(a) A hole is created at the next location
Fig. 3.7.6 (b) Percolate the hole up to satisfy heap order
| ||
| ||
Data Structures 3.58 | ||
![]() |
![]() |
![]() |
Fig. 3.7.6 (c) Percolate the hole up to satisfy heap order
Fig. 3.7.6 (d) Percolate the hole up to satisfy heap order In Fig 3.6.6(d) the value 10 is placed in its correct location. DeleteMin DeleteMin Operation is deleting the minimum element from the Heap. In Binary heap the minimum element is found in the root. When this minimum is removed, a hole is created at the root. Since the heap becomes one smaller, makes the last element X in the heap to move somewhere in the heap. If X can be placed in hole without violating heaporder property place it. Otherwise, we slide the smaller of the hole's children into the hole, thus pushing the hole down
one level.
| ||
| ||
Data Structures 3.59 | ||
![]() |
![]() |
![]() |
We repeat until X can be placed in the hole. This general strategy is known as perculate down. Example: To delete the minimum element 10
Delete Minimum element 10, creates the hole at the root.
The last element `30' must be moved somewhere in the heap.
| ||
| ||
Data Structures 3.60 | ||
![]() |
![]() |
![]() |
The Hole's smallest children (12) is placed into the hole by pushing the hole down one level.
The hole's smallest children (20) is placed into the hole by pushing the hole one level down.
The last element `30' is placed in the correct hole.
Fig. 3.7.7
| ||
| ||
Data Structures 3.61 | ||
![]() |
![]() |
![]() |
ROUTINE TO PERFORM DELETEMIN IN A BINARY HEAP int Deletemin (PriorityQueue H) { int i, child; int MinElement, LastElement; if (IsEmpty (H)) { Error ("Priority queue is Empty"); return H } MinElement = H LastElement = H for (i = 1; i * 2 < = H { /* Find Smaller Child */ child = i * 2; if (child ! = H < H child + +; // Percolate one level down if (LastElement > H H else break ; } H return MinElement; } | ||
| ||
Data Structures 3.62 | ||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
OTHER HEAP OPERATIONS The other heap operations are (i) Decrease - key (ii) Increase - key (iii) Delete (iv) Build Heap DECREASE KEY The Decreasekey (P, example : Priority Queue H
Fig. 3.7.8 (a) Decrease Key(2, 7, H) Element at position 2 is `15'. Decrease that element by 7. Now the position 2 has the value `8', which violates the heap order property. This can be fixed by percolating up strategy. | ||||||||
| ||||||||
Data Structures 3.63 | ||||||||
![]() |
![]() |
![]() |
Increase - Key The increase - key (p, example : Priority Queue H
Increase Key (2, 7, H)Fig. 3.7.9 (a) Here, the Element at position 2 is 15. Increase that value by 7. Now the position 2 has the value 22, which violates the heap order property. This can be fixed by percolate down.
Delete : The Delete (P, H) operation removes the node at the position P from the heap H. This can be done by. (i) Perform the decreasekey operation Decreasekey (P, (ii) Perform Deletemin operation DeleteMin (H) | ||
| ||
Data Structures 3.64 | ||
![]() |
![]() |
![]() |
eg : - Delete (2, (i) Decreasing by Infinity
After Decreasing the value at position 2 by
Fig. 3.7.10 Binary heap satisfying heap order property since `- (ii) DeleteMin After deleting the minimum element, the last element will occupy the hole. Then will occupy the hole. Then rearrange the heap till it satisfies heap order property.
Build Heap The Build Heap (H) operations takes as input N keys and places them into an empty heap
by maintaining structure property and heap order property.
| ||
| ||
Data Structures 3.65 | ||
![]() |
![]() |
![]() |
Questions Part - A 1. Compare General Tree and binary tree? 2. Define the following terminologies in a tree (1) Siblings, parent (2) Depth, Path (3) Height, Degree 3. What is complete binary tree? 4. Define Binary Search Tree. 5. Give the array and linked list representation of tree with an example. 6. Show that the maximum number of nodes in a binary tree of height H as 2H + 1 -1. 7. Define Tree Traversal. 8. Give the preorder form for the following Tree.
9. Write a routine to find the minimum element in a given tree. 10. Write the recursive procedure for inorder traversals. 11. Draw a binary search tree for the following input lists. 60, 25, 75, 15, 33, 44 2. How is a binary tree represented using an array? 13. Define AVL tree. 14. What are the two properties of a binary heap. 15. Define (i) Hashing (ii) Collision (iii) Hash function. 16. What is open addressing? 17. Write a routine to perform single rotate with left.
| ||
| ||
Data Structures 3.66 | ||
![]() |
![]() |
![]() |
18. List the operations performed on priority Queue. 19. Differentiate between binary tree and Binary search tree. 20. Differentiate between general tree and binary tree. Part B 1. (a) Write an algorithm to find an element from binary search tree. (b) Write a program to insert and delete an element from binary search tree. 2. Write a routine to generate the AVL tree. 3. What are the different tree traversal techniques? Explain with examples. 4. Write a function to perform insertion and deletemin in a binary heap. 5. Define Hash function. Write routines to find and insert an element in seperate chaining. | ||
| ||
Data Structures 3.67 | ||
![]() |
![]() |
![]() |
/*PROGRAM FOR FIND,FINDMIN,FINDMAX */
#include<stdio.h> #include<stdlib.h> #include<conio.h> typedef struct tree *node ; node insert(int,node T); void Find(node T,int); void FindMin(node T); void FindMax(node T); struct tree { int data; struct tree *right,*left; }*root;
void main() { node T =NULL; int data,s,i=0,n; char c; clrscr(); printf("\nEnter Number of elements in the tree\n"); scanf("%d",&n); printf("Elements are :\n"); while(i<n) { scanf("%d",&data); T=insert(data,T); i++; } printf("Enter the element to search :"); scanf("%d",&s); Find(T,s); FindMin(T); FindMax(T); getch(); } node insert(int X, node T) { struct tree *newnode; | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
newnode=malloc(sizeof(struct tree)); if(newnode==NULL) printf("Out of Space\n"); else { if(T==NULL) { newnode->data=X; newnode->left=NULL; newnode->right=NULL; T=newnode; } else { if(X<T->data) T->left=insert(X,T->left); else T->right=insert(X,T->right); } } return T; }
void Find(node T,int X) { if(T==NULL) printf("Search Element not found"); else { if(T->data==X) printf("Search Element %d is Found",X); else if(X< T->data) Find(T->left,X); else Find(T->right,X); } } void FindMin(node T) { if(T!=NULL) { if(T->left==NULL) | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
printf("\nThe Minimum Element in the Tree is %d",T->data); else FindMin(T->left); } } void FindMax(node T) { if(T!=NULL) else FindMax(T->right); } }
SAMPLE INPUT AND OUTPUT:-
Enter Number of elements in the tree 5 Elements are : 20 10 30 5 40 Enter the element to search :10 Search Element 10 is Found The Minimum Element in the Tree is 5 The Maximum Element in the Tree is 40
/*PROGRAM TO IMPLEMENT DELETION ON BINARY SEARCH TREE */
#include<stdio.h> #include<stdlib.h> #include<conio.h> typedef struct tree *node ; node insert(int,node T); node FindMin(node T); node del(int,node T); void display(node T); struct tree { int data; | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
struct tree *right,*left; }*root;
void main() { node T =NULL; int data,n,i=0; char c; clrscr(); printf("Enter the number of elements in the Tree:"); scanf("%d",&n); printf("\nEnter the elements\n"); while(i<n) { scanf("%d",&data); T=insert(data,T); i++; } printf(" Elements displayed in Inorder format\n"); display(T); printf("\nEnter the element to Delete\n"); scanf("%d",&data); T=del(data,T); printf("\nContents of Tree after deletion\n"); display(T); getch(); } node insert(int X, node T) { struct tree *newnode; newnode=malloc(sizeof(struct tree)); if(newnode==NULL) printf("Out of Space\n"); else { if(T==NULL) { newnode->data=X; newnode->left=NULL; newnode->right=NULL; T=newnode; | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
} else { if(X<T->data) T->left=insert(X,T->left); else T->right=insert(X,T->right); } } return T; } node del(int X, node T) { node TmpCell; if(T==NULL) printf("Element not found"); // exit(0); else /* To find the element to delete */ if(X<T->data) T->left=del(X,T->left); else if(X>T->data) T->right=del(X,T->right); else /*Found element to be deleted */ if(T->left && T->right) /* Two children */ { TmpCell = FindMin(T->right); T->data=TmpCell->data; T->right=del(T->data,T->right); } else /* one or zero children */ { TmpCell =T; if(T->left==NULL) T=T->right; else if(T->right==NULL) T=T->left; free(TmpCell); } return T; | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
}
node FindMin(node T) { if(T!=NULL) { if(T->left==NULL) return T; else return FindMin(T->left); } return(0); } void display(node T) { if(T!=NULL) { display(T->left); printf("%d\t",T->data); display(T->right); } }
SAMPLE INPUT AND OUTPUT:- Enter the number of elements in the Tree:5
Enter the elements 35 23 10 45 30 Elements displayed in Inorder format 10 23 30 35 45 Enter the element to Delete 23
Contents of Tree after deletion 10 30 35 45 | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
/* PROGRAM FOR BINARY TREE TRAVERSAL */
#include<stdio.h> #include<stdlib.h> #include<conio.h> typedef struct tree *node ; node insert(int,node T); void inorder(node T); void preorder(node T); void postorder(node T); struct tree { int data; struct tree *right,*left; }*root;
void main() { node T =NULL; int data,ch,i=0,n; clrscr(); printf("\nEnter the number of elements in the Tree:"); scanf("%d",&n); printf("\nThe Elements are :\n"); while(i<n) { scanf("%d",&data); T=insert(data,T); i++; } printf("1. INORDER\t 2.PREORDER\t 3.POSTORDER\t4.EXIT"); do { printf("\nEnter your choice:"); scanf("%d",&ch); switch(ch) { case 1: printf("Inorder traversal of the given Tree \n"); inorder(T); break; case 2: printf("Preorder traversal of the given Tree \n"); | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
preorder(T); break; case 3: printf("Postorder traversal of the given Tree \n"); postorder(T); break; default : printf("Exit"); exit(0); }
}while(ch<4); getch(); } node insert(int X, node T) { struct tree *newnode; newnode=malloc(sizeof(struct tree)); if(newnode==NULL) printf("Out of Space\n"); else { if(T==NULL) { newnode->data=X; newnode->left=NULL; newnode->right=NULL; T=newnode; } else { if(X<T->data) T->left=insert(X,T->left); else T->right=insert(X,T->right); } } return T; } void inorder(node T) { if(T!=NULL) | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
{ inorder(T->left); printf("%d\t",T->data); inorder(T->right); } } void preorder(node T) { if(T!=NULL) { printf("%d\t",T->data); preorder(T->left); preorder(T->right); } } void postorder(node T) { if(T!=NULL) { postorder(T->left); postorder(T->right); printf("%d\t",T->data); } }
SAMPLE INPUT AND OUTPUT:
Enter the number of elements in the Tree:4
The Elements are : 30 20 40 25 1. INORDER 2.PREORDER 3.POSTORDER 4.EXIT | ||
| ||
Data Structures | ||
![]() |
![]() |
![]() |
Enter your choice:1 Inorder traversal of the given Tree 20 25 30 40 Enter your choice:2 Preorder traversal of the given Tree 30 20 25 40 Enter your choice:3 Postorder traversal of the given Tree 25 20 40 30 Enter your choice:4 | ||
| ||
Data Structures | ||