Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
M7.1: Introduction: A tree is a non-linear data structure in which items are arranged in a sorted sequence. It is used to represent hierarchical relationship existing amongst several data items. We can define the tree as: “A tree is a non-linear data structure which is a finite set of one or more nodes such that” 1. there is a special designated node, called the root R of the tree 2. and its remaining nodes are partitioned into number of disjoint subsets (n>=0), each of which is itself a tree, such as T1, T2, …., Tn. These are called as subtrees. (Fig M7.1: Examples of Tree data-structure) Natural trees grow upwards from the ground into the air. But, tree data structure grows downwards from top to bottom as shown in figure M7.1. It is an universally practiced convention for trees. Page 1 www.magix.in M7.2: Tree Terminology: Let’s first consider some of the basic terms that we need to know first if wanna know the tree data structure further: (Fig M7.2: Tree data structure) 1. Node: Each data item in a tree is basically represented by a node. A tree node is a collection of data information and branches (links) to other data items. Upper figure M7.2 has 6 number of nodes. ] 2. Root Node: There is always a designated node, called root node in a tree data structure. It is the very first node in the hierarchical arrangement of tree nodes. In following figure ‘A’ is the root node. (Fig M7.3: Hierarchical structure of a tree) 3. Degree of a Node: The number of subtrees (children) of a node is called its degree. In above figure, the degree of A is 3, the degree of B is 1, the degree of C is 2, the degree of D is one and the degree of H is 3. 4. Degree of a Tree: The degree of a tree is the maximum of its element degrees. The degree of a tree, shown in above figure is 3. Page 2 www.magix.in 5. Leaf or Terminal or External Node: Nodes that have zero degree are called as leaf nodes or terminal nodes. In above figure, E, F, G, I, J and K are leaf nodes. 6. Non-Terminal or Internal Node: Nodes that have one or more than one degree are called as non-terminal nodes. In above figure A, B, C, D, and H are non-terminal nodes. 7. Sibling: Children of the same parent are called as siblings. In above figure M7.3: Ø B, C and D are siblings of node A Ø F and G are siblings of C and I Ø J and K are siblings of H. 8. Level: Each node is assigned a level number in such a way that the root node is always at level 1, its immediate children are at level 2 and their immediate children are at level 3 and so on up to the leaf nodes. It means that if a node is at ith level then its children are at (i+1)th level. 9. Height/ Depth of a Tree: If level of the root is denoted by 1, then the maximum level number of the tree is known as its ‘height’ or ‘depth’. 10. Subtree: A subtree is a portion of a tree data structure that can be viewed as a complete tree in itself. Any node in a tree ‘T’, together with all the nodes below it, comprise a subtree of T. The subtree corresponding to the root node is the entire tree; the subtree corresponding to any other node is called a proper subtree. 11. Edge: It is a connecting line of two nodes. That is, the line drawn from one node to another node is called an ‘edge’. 12. Path: It is a sequence of consecutive edges from the source node to the destination node. In the above tree M7.3, the path between A and J is given by the node pairs: (A, D) , (D, H) and (H, J) 13. Forest: It is a set of disjoint trees. In a given tree, if you remove its root node then it becomes a forest. In the above tree M7.3, if we remove the root node ‘A’, there is forest with three trees. Page 3 www.magix.in M7.3: Binary Tree: In computer science, a binary tree is a tree data structure in which each node has at most two children. Typically the first node is known as the parent and the child nodes are called left and right. The essential differences between a binary tree and a tree are: Ø A binary tree can be empty whereas a tree cannot. Ø Each element in binary tree has at most two subtrees (one or both of these subtrees may be empty). Each element in a tree can have any number of subtrees. Ø The subtrees of each element in a binary tree are ordered. That is, we distinguish between the left and right subtrees. The subtrees in a tree are unordered. Like a tree, a binary tree is drawn with its root at the top. The elements in the left (/right) subtree of the root are drawn below and to the left (/right) of the root. Between each element and its children is a line or edge. (Fig M7.4: Some of the combinations for binary trees) (Fig M7.5: Another example of binary tree with data nodes) Page 4 www.magix.in Some Properties of Binary Trees: Property 1: A binary tree with ‘n’ elements, n>0, has exactly n-1 edges. Proof: Every element in a binary tree, except the root, has exactly one parent. There is exactly one edge between each child and its parent. So the number of edges is ‘n-1’. Property 2: A binary tree of height ‘h’, h>0, has at least ‘h’ and at most 2h-1 Proof: elements in it. Since there must be at least one element at each level, the number of elements is at least ‘h’. As each element can have at most two children, the number of elements at level ‘k’ is at most 2k-1 for k>0. For h=0, the total number of elements is 0, which equals 20-1. For ‘h>0’, the total number of elements cannot exceed :- M7.4: Types of Binary Trees: Binary trees are again classified in some categories on the base of their certain characteristics. Let’s discuss some of them: M7.4.1: Full Binary Tree: A binary tree of height ‘h’ that contains 2h-1 elements is called a “full binary tree”. The binary tree of figure M7.6(a) is a full binary tree whereas the binary tree of figure M7.6(b) is not a “full binary tree” Fig M7.6 (b) A binary tree which is not full. Page 5 www.magix.in M7.4.2: Complete Binary Tree: A complete binary tree is a special case of a binary tree, in which all the levels, except perhaps the last, are full; while on the last level, any missing nodes are to the right of all the nodes that are present. For example, we could have: Or even this But we don't want are trees like: Page 6 www.magix.in M7.4.3: Strictly Binary Tree: A binary tree is strictly binary tree if every node in the tree is either 0 or 2, then the tree is said to be “strictly binary tree”. i.e., each node can have maximum two children or no children (no children indicate empty ‘left’ and empty ‘right’ child). (Fig M7.7: An example of Strict binary tree) M7.4.4: Tournament Tree/ Selection Tree: Suppose ‘n’ players enters in a chess tournament and further suppose that the tournament is played on knock-out basis. By knock-out basis means a player is eliminated from the tournament upon losing a match. Pairs of players play each other until only one remains undefeated. The undefeated player is declared winner of the tournament. Following figure shows a possible tournament involving eight players with some numeric numbering. The tournament is described by a binary tree in which each external node (leaf node) represents a player and each internal node represents a match played between players designated by the children of the node. The tournament tree is described by a complete binary tree: Ø Each external node represents a player Ø Each internal node represents a match played Ø Each level of internal nodes defines a round of matches (Fig 7.8: 8 player tournament tree) Page 7 www.magix.in There are two types of tournament trees: ‘Winner trees’ and ‘loser trees’. The tree in above figure are called “winner trees” because at each internal node, we record the winner of the match played at that node. In contrast, if we record the loser of the match played at that node, the tournament tree is called a “loser tree”. Tournament trees are also called “selection trees”. (Fig 7.9: 8 player loser tree) M7.4.5: Binary Search Trees (BST): A binary search tree ‘T’ is a binary tree that may be empty. A nonempty binary search tree satisfy the following properties: 1. Every element has a key (or value) and no two elements have the same key. i.e. all keys are unique. 2. The keys, if any, in the left subtree of the root are smaller than the key of the root. 3. The keys, if any, in the right subtree of the root are larger than the key in the root. 4. The left and right subtrees of the root are also binary search trees. Let’s have some example for this. Following figures shows different possible combination of BST with same key values: Page 8 www.magix.in (Fig 7.10: Examples of BST) M7.5: Representation of Binary Trees and BST: It is often required to maintain binary trees in the computer memory. There are two traditional popular techniques that are used to maintain binary trees in the memory. These are: Ø Sequential representation Ø Linked List representation 1. Sequential Representation: A sequential representation of a binary tree requires numbering of nodes; starting with nodes on level 1, then on level 2 and so on. The nodes are numbered from left to right. One thing to notice is that numbering of nodes is always done considering a complete binary tree. i.e. following figure shows the numbering of a tree with height 4. (Fig 7.11: Numbering of nodes in a binary tree) Page 9 www.magix.in Now the binary (or BST) tree is represented by storing each element at the array position corresponding to the number assigned. In this representation, a binary (search) tree having ‘n’ levels may require an array of size (2n-1). For simplicity, we will consider that array is indexed with an index set beginning from 1 not from 0. Now let’s take an example: can be represented in a array as: Lets take another example: (Fig 7.12: Example for array representation of binary tree) Page 10 www.magix.in Now imagine how the following binary search tree will stored in array representation: (a) A right-skewed binary search tree The array representation of binary search tree of above figure is shown in following figure: (Fig 7.13: b: Array representation of upper BST) This scheme of representation is quite wasteful of space when the binary (or BST) tree is skewed or number of elements is small as compared to its height. Hence, array representation is useful only when the binary (or BST) tree is full or complete. 2. Link-List Representation: The most popular and practical way of representing a binary (or BST) tree is using linked-list (pointers). For example, the binary tree: (a) A binary tree Page 11 www.magix.in Can be represented using linked list as: And the tree can be represented in linked list form as: In linked representation, each element is represented by a node that has exactly two link fields. Let us call these fields ‘left’ and ‘right’. In addition to these two link fields, each node has a data field called ‘info’. This node structure is defines as : struct nodeType { struct nodeType *left ; int info ; struct nodeType *right ; }; Page 12 www.magix.in Each node in the drawing of a binary tree is represented by a pointer from the parent node to the child node. This pointer is placed in the appropriate link field of the parent node. Since an ‘n’ element binary tree has exactly ‘n-1’ edges, there will be 2n-(n-1) = n+1 link fields that have NULL values (pictured as X). In addition to the above node structure, a pointer variable, say ‘root’, is used to keep track of the root of the binary tree. We can access all the nodes in binary tree starting at the root and following ‘left’ and ‘right’ links. M7.6: Creation of an BST: Q.-> Draw a binary search tree for the following string considering each character as information of the node in a binary search tree: COMPUTER Solution: Initially the BST (Binary Search Tree) is empty. First character from the string is ‘C’. It becomes the root of the tree. So, the BST is: C Next character from the string is ‘O’. This character is compared with the root character ‘C’, it is greater than ‘C’. As the right pointer of ‘C’ node is NULL. The node with information ‘O’ becomes the right node of ‘C’. So, the BST now is: C O Next character is ‘M’. This character is compared with ‘C’. ‘M’ is greater than ‘C’. Right pointer of ‘C’ is not equal to NULL. So ‘M’ is compared with ‘O’. Now ‘M’ is less than ‘O’ and the left pointer ‘O’ is NULL, so the node with information ‘M’ becomes left node of ‘O’. So, the BST is: C O M Page 13 www.magix.in Next character is ‘P’. This character is first compared with the root information of BST. It is greater than root information that is ‘C’. It is also greater than the right node information ‘O’. As the right pointer of ‘O’ is NULL, the node that is to be inserted in BST becomes the right node of ‘O’. So, now the BST is: C O P M The next character is ‘U’. It is greater than ‘C’, ‘O’ and ‘P’. The right pointer of node with information ‘P’ is equal to NULL, so the new node with information ‘U’ is inserted as the right node of ‘P’. So, the BST becomes: C O P M U The next character is ‘T’. It is greater than ‘C’, ‘O’, and ‘P’ but less than ‘U’. The left pointer of node ‘U’ is NULL, so the new node with information ‘T’ is inserted to the left of ‘U’. So, the BST becomes: C O M P U T Page 14 www.magix.in The next character is ‘E’. It is greater than ‘C’, less than ‘O’ and less than ‘M’. The left pointer of the node ‘M’ is NULL, so the new node with information ‘E’ is inserted as left node of ‘M’. So the BST becomes: C O P M U E T The next and last character is ‘R’. It is greater than ‘C’, ‘O’, and ‘P’ but less than ‘U’ and ‘T’. The left pointer of ‘T’ is equal to NULL, so the last new node with information ‘R’ becomes the left node of ‘T’. So, the final BST is: C O P M U E T R Q.2: Draw a binary search tree considering the month name as the information of a binary search tree node, for the following list of month names of year: Jun, Sep, Jan, Mar, Feb, Dec, Aug, Oct, Nov, Jul, May, Apr Solution: The order of month-name is Jan, Feb, Mar etc. The first name in the list is ‘Jun’. It is the root of the binary search tree. The next name is ‘Sep’; it is compared with the root node, which is greater than root node, so it forms the right node of root. Similarly all the elements are compared and inserted into the binary search tree at proper places. Step by step drawing of the binary search tree is as follows: Page 15 www.magix.in Page 16 www.magix.in M7.7: Common Operations on Binary Trees & BSTs: Some of the operations that are commonly performed on binary as well as binary search trees are: 1. Create an empty tree 2. Traverse it. 3. Determine its height 4. Determine the number of elements in it. 5. Determine the number of internal nodes i.e. non-leaf nodes. 6. Determine the number of external nodes i.e. leaf nodes. 7. Remove it from memory. Page 17 www.magix.in The following are some the operations having relevance to only binary Search trees: 1. Insert a new node/element. 2. Search an element. 3. Find the smallest element. 4. Find the largest element. 5. Delete a node. In our implementation of binary (or BST) tree, we will consider following declarations: typedef struct nodeType { struct nodeType *left ; int info ; struct nodeType *right ; } BST ; BST *root ; Here, we have defined a new data type and given it a name BST, then we have declared a pointer variable ‘root’ to represent the binary (search) tree. M7.7.1: Creating an Empty Binary (Search) Tree: Since the binary (Search) tree will be empty in the beginning, the variable ‘root’ is assigned a sentinel value to indicate that binary (search) tree is empty. The following listing shows the implementation of this function: void CreateTree ( BST **tree) { *tree = NULL ; } M7.7.2: Traversing Binary (Search) Tree: Traversing means visiting each node exactly once. A full traversal of a binary tree ‘T’ produces a linear order of elements existing in ‘T’. There are three basic ways for traversing a binary tree: 1. Pre-Order traversal: The traversal order is: Ø Process the root R Ø Traverse the left subtree of R in pre-order Ø Traverse the right subtree of R in pre-order 2. In-Order traversal: The traversal order is: Ø Traverse the left subtree of R in In-order Ø Process the root R Ø Traverse the right subtree of R in In-order Page 18 www.magix.in 3. Post-Order traversal: The traversal order is: Ø Traverse the left subtree of R in post-order Ø Traverse the right subtree of R in post-order Ø Process the root R In addition to above standard traversal schemes, there is another possible traversal scheme known as “Level-order traversal”. As its name suggests, in this scheme first node at level 1, i.e., root is traversed, then nodes at level2 followed by nodes at level3, … , and so on. Example: Consider the following binary tree T: In this binary tree: a) Preorder traversal yields: b) Post-order traversal yields: c) In-order traversal yields: d) level-order traversal yields: a) 2, 7, 2, 6, 5, 11, 5, 9, 4 2, 5, 11, 6, 7, 4, 9, 5, 2 2, 7, 5, 6, 11, 2, 5, 4, 9 2, 7, 5, 2, 6, 9, 5, 11, 4 Pre-Order Traversal of a Binary (Search) Tree: Following listing shows the recursive implementation of pre-order traversal algorithm: void preorderTraversalRecursive ( BST *tree ) { if ( tree != NULL ) { printf( “ %d ”, tree -> info ) ; preorderTraversalRecursive ( tree -> left ) ; preorderTraversalRecursive ( tree -> right ) ; } } Page 19 www.magix.in Algorithm for pre-order recursive: Algorithm PreOrderRecursive (PTR) Here PTR is a pointer contains the address of root node. Step1: Begin Step2: if (PTR <> NULL) then Step2.1: Write: PTR -> info Step2.2: Call PreOrderRecursive (PTR-> LEFT) Step2.3: Call PreOrderRecursive (PTR-> RIGHT) Step2.4: Endif Step3: End b) In-Order Traversal of a Binary (Search) Tree: The following listing shows the recursive implementation of in-order traversal algorithm: void inorderTraversalRecursive ( BST *tree) { if ( tree != NULL ) { inorderTraversalRecursive ( tree -> left ) ; printf ( “ %d “ , tree -> info ) ; inorderTraversalRecursive ( tree -> right ) ; } } Algorithm for In-order recursive: Algorithm InOrderRecursive (PTR) Here PTR is a pointer contains the address of root node. Step1: Begin Step2: if (PTR <> NULL) then Step2.1: Call InOrderRecursive (PTR-> LEFT) Step2.2: Write: PTR -> info Step2.3: Call InOrderRecursive (PTR-> RIGHT) Step2.4: Endif Step3: End c) Post-Order Traversal of a Binary (Search) Tree: Following listing shows the recursive implementation of post-order traversal algorithm: void postorderTraversalRecursive ( BST *tree ) { if ( tree != NULL ) { postorderTraversalRecursive ( tree -> left ) ; postorderTraversalRecursive ( tree -> right ) ; printf( “ %d ”, tree -> info ) ; } } Page 20 www.magix.in Algorithm for post-order recursive: Algorithm PostOrderRecursive (PTR) Here PTR is a pointer contains the address of root node. Step1: Begin Step2: if (PTR <> NULL) then Step2.1: Call PostOrderRecursive (PTR-> LEFT) Step2.2: Call PostOrderRecursive (PTR-> RIGHT) Step2.3: Write: PTR -> info Step2.4: Endif Step3: End d) Level-Order Traversal of a Binary (Search) Tree: The following listing shows the implementation of level-order traversal algorithm: void levelorderTraversal ( BST *tree ) { queue *q ; BST *ptr ; createQueue ( &q ) ; enqueue ( &q , tree ) ; while ( ! isEmpty ( q ) ) { ptr = dequeue ( &q ) ; if ( ptr -> left != NULL ) enqueue ( &q, ptr -> left ) ; if ( ptr -> right != NULL ) enqueue ( &q , ptr -> right ) ; printf ( “ %d “ , ptr -> info ) ; } } Algorithm for level-order traversal: Algorithm LevelOrderTraversal (Tree) Here TREE is a pointer contains the address of root node. It use a queue ‘q’ whose elements are pointers to type BST. It uses a temporary pointer variable ‘ptr’ to hold the address of current node. Step1: Begin Step2: CreateEmptyQueue (q) //Call procedure to create an empty queue Step3: enqueue ( q, tree ) // enqueu NULL value as sentinel value Step4: While ( q is not Empty ) do Step4.1: Set ptr := dequeue ( q ) Step4.2: if ( ptr -> left != NULL ) then Step4.2.1: enqueue ( q, ptr -> left ) Step4.2.2: End if Step4.3: if ( ptr -> right != NULL ) Step4.3.1: enqueue ( q, ptr -> right ) Step4.3.2: end if Step4.4: Print : ptr -> info Step4.5: End while Step5: End Page 21 www.magix.in Construction of Binary Tree: Binary tree has one very interesting property – property is that if we are given “inorder traversal” and either of “pre-order” or “post-order” traversals, we can construct the binary tree from these traversals. Example: Consider that a binary tree ‘T’ has 8 nodes. The pre-order and in-order traversals of binary tree ‘T’ yield the following sequence of nodes: Pre-order : In – Order : A D B B D G E G E H H A C C F F Draw the binary tree. Solution: The binary tree ‘T’ is drawn as follows: The first node in the pre-order traversal is always a root node of the binary tree. Thus the root node of the binary tree T is node ‘A’. After determining the root node of the binary tree, our aim is to find the nodes that comprise the left subtree and right subtree of node ‘A’. We know from the in-order traversal that first left subtree is traversed, then root node, and finally the right subtree. Thus all the nodes to the left of node ‘A’ in in-order traversal comprise its left subtree. Similarly, all the nodes to the right of node ‘A’ in inorder traversal comprise its right subtree. The above procedure partitions the pre-order and in-order traversal sequences as shown below: Page 22 www.magix.in Following figure shows the partial binary tree constructed so far: In the same way, we can construct the left subtree LTB and right subtree RTB. Let us first consider the left subtree LTA. The pre-order and in-order traversal sequences of the left subtree LTA are: Pre-order: B D E G H In-Order : D B G E H From these traversal sequences we find that the root of the subtree is node B, and its left subtree consists of a single node D and the right subtree consists of nodes G, E, and H. The above procedure partitions the pre-order and in-order sequences as shown below: Following figure shows the partial binary tree constructed so far: Page 23 www.magix.in Now consider the right subtree RTB. The pre-order and in-order traversal sequences of RTB are: Pre-order: E G H In-order: G E H From these traversal sequences we find that the root of the subtree RTB is node ‘E’, and its left subtree consists of a single node ‘G’ and the right subtree also consists of a single node ‘G’. The above procedure partitions the pre-order and in-order traversal sequences of RTB as shown below: Following figure shows the partial binary tree constructed so far: Thus we have completed the construction of the left subtree LTA of node ‘A’, which was the root node of the binary tree. Page 24 www.magix.in Now we are left with the right subtree RTA. The pre-order and in-order traversal sequences of RTA are: Pre-order: C F In-order: C F From these traversal sequences we find that the root of the subtree RTA is node ‘C’, and its left subtree is empty and the right subtree consists of a single node ‘F’. The above procedure partitions the pre-order and in-order traversal sequences of RTA as shown below: Following figure shows the binary tree after this step, and this is the final binary tree: (Final binary tree) Note: The above procedure can be easily modified if the in-order and the post-order traversals of a binary tree are given. The only difference is that the root of the tree will be appearing as the last node in the post-order traversal. Exercise: Consider that a binary tree ‘T’ has 8 nodes. The post-order and in-order traversals of binary tree ‘T’ yield the following sequence of nodes: In – Order : D B G E H A C F Post-order : D G H E B F C A Draw the binary tree. Page 25 www.magix.in M7.7.3: Determining Height of Binary (Search) Tree: In order to determine the height of a binary (search) tree, we find the height of the ‘left subtree’ and ‘right subtree’ of a given node. The height of the binary (search) tree at a given node will be equal to maximum height of the left and right subtrees plus 1. The following listing shows the implementation of the various steps required: int determineHeight (BST *tree) { int leftHeight, rightHeight ; if ( tree == NULL ) return 0 ; else { leftHeight = determineHeight ( tree -> left ) ; rightHeight = determineHeight ( tree -> right ) ; if ( leftHeight > rightHeight ) return ++leftHeight ; else return ++rightHeight ; } } Algorithm for Determining height of a bst: Algorithm DetermineHeight (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( Tree is NULL) Step2.1: Return 0 Step3: Else Step3.1: Leftheight = Call DetermineHeight( tree->left) Step3.2: Rightheight = Call DetermineHeight( tree->right) Step3.3: if ( Leftheight > Rightheight ) Step3.3.1: Return Leftheight+1 Step3.4: else Step3.4.1: Return Rightheight+1 Step3.4.2: end if Step3.5: End If Step4: END Page 26 www.magix.in M7.7.4: Determining Number of Nodes/ Elements in a Binary (Search) Tree: The number of elements/Nodes in a binary (search) tree is equal to the number of nodes in the ‘left subtree’ plus number of nodes in the ‘right subtree’ of a given node plus 1. If the binary (search) tree is empty, then the number of nodes is equal to 0. The following listing shows the implementation of the various steps required for this approach: int TotalNodes ( BST *tree ) { if ( tree == NULL ) return 0 ; else return ( TotalNodes ( tree->left) + TotalNodes ( tree-> right) + 1 ) ; } Algorithm for Determining number of nodes in a bst: Algorithm TotalNodes (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( Tree is NULL) Step2.1: Return 0 Step3: Else Step3.1: Return ( TotalNodes(tree->left) + TotalNodes(tree->right) + 1 ) Step3.2: End If Step4: END M7.7.5: Determining Number of Internal Nodes in a Binary (Search) Tree: The number of internal elements/Nodes in a binary (search) tree is equal to the number of internal/non-leaf nodes in the ‘left subtree’ plus number of non-leaf nodes in the ‘right subtree’ of a given node plus 1. If the binary (search) tree is empty, then the number of internal nodes is equal to 0. The following listing shows the implementation of the various steps required for this approach: int internalNodes ( BST *tree ) { if ( ( tree == NULL ) || ( ( tree->left == NULL) && (tree->right == NULL) ) ) return 0 ; else return ( internalNodes ( tree->left) + internalNodes ( tree-> right) + 1 ) ; } Page 27 www.magix.in Algorithm for Determining number of internal nodes in a bst: Algorithm InternalNodes (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( ( Tree is NULL) OR (tree->left AND tree->right is NULL) ) Step2.1: Return 0 Step3: Else Step3.1: Return ( InternalNodes(tree->left) + InteranalNodes(tree->right) + 1 ) Step3.2: End If Step4: END M7.7.6: Determining Number of External Nodes in a Binary (Search) Tree: The number of external elements/Nodes in a binary (search) tree is equal to the sum of the external in the left subtree and the external nodes in the right subtree of a given node. Note that if the binary (search) tree is empty then the number of external nodes is 0 and if there is only one node in the binary (search) tree then the number of external node is equal to 1. The following listing shows the implementation of the various steps required for this approach: int externalNodes ( BST *tree ) { if( tree== NULL ) return 0 ; else if ( ( tree->left == (BST *)NULL) && (tree->right==(BST *) NULL) ) return 1 ; else return ( externalNodes ( tree->left) + externalNodes ( tree-> right) ) ; } Algorithm for Determining number of external nodes in a bst: Algorithm externalNodes (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( Tree is NULL ) Step2.1: Return 0 Step2.2: Else if ( tree->left AND tree -> right is NULL) Step2.2.1: Return 1 Step2.3: Else Step2.3.1: Return ( externalNodes(tree->left) + externalNodes(tree->right) ) Step2.4: End If Step3: END Page 28 www.magix.in M7.7.7: Removing Binary (Search) Tree from memory: Before a program using binary (search) tree represented using linked representation terminates, the binary (search) tree must be removed from memory. To accomplish this task, first we delete the left subtree and then right subtree and then node, recursively. The following listing shows the implementation of the various steps required: void removeTreeFromMemory ( BST **tree ) { if ( *tree != NULL ) { removeTreeFromMemory (& (*tree ) -> left ) ; removeTreeFromMemory (& (*tree ) -> right ) ; free( *tree ) ; } } Algorithm for Removing binary (search) tree from memory: Algorithm removeFromMemory (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( Tree is NOT NULL ) Step2.1: removeFromMemory ( tree -> left ) Step2.2: removeFromMemory ( tree -> right ) Step2.3: freeNode( tree ) Step2.4: End if Step3: END TILL NOW WE HAVE SEEN OPERATION THAT ARE COMMON TO NORMAL BINARY TREES AND BINARY SEARCH TREES. NOW WE WILL DISCUSS SOME OF THE OPERATIONS THAT WILL WORK ONLY FOR BINARY SEARCH TREE. SO DON’T TRY TO RUN FOLLOWING OPERATIONS ON SIMPLE BINARY TREES. M7.7.8: Inserting a new element in the Binary Search Tree (BST) : If the binary search tree is initially empty, then the element is inserted as root node; otherwise the new element is inserted as a terminal node. If the element is less than the element in the root node, then the new element is inserted in the left subtree else right subtree. Consider the BST shown below: Page 29 www.magix.in Suppose the node pointed to by temp (with item 140) has to be inserted. The item 140 is compared with root node 100. Since it is greater, the right subtree of root node has to be considered. Now compare 140 with 200 and since it is less, consider the left subtree of the node 200. Now, compare 140 with 150. Since it is less, consider the left subtree of node 150. Since, left subtree of node 150 is empty; the node containing the item 140 has to be inserted towards left of a node 150. Thus, to find the appropriate place and insert an item, the search should start from the root node. The following listing shows the implementation of the various steps required: void insertElementIterative ( BST **tree , int element ) { BST *ptr, *nodePtr, *parentPtr ; ptr = (BST * ) malloc ( sizeof(BST) ) ; ptr -> info = element ; ptr -> left = ptr -> right = NULL ; if ( *tree == NULL ) *tree = ptr ; else { parentPtr = NULL ; nodePtr = *tree ; while ( nodePtr != NULL ) { parentPtr = nodePtr ; if ( element < nodePtr->info ) nodePtr = nodePtr -> left ; else nodePtr = nodePtr -> right ; } if ( element < parentPtr -> info ) parentPtr -> left = ptr ; else parentPtr -> right = ptr ; } } Page 30 www.magix.in Algorithm for Inserting a New Element: Algorithm InsertElement (Tree, element) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: Step3: Step4: Step5: Step5.1: Step5.2: Step5.2.1: Step5.2.2: Step5.2.3: Step5.2.3.1: Step5.2.3.2: Step5.2.3.2.1: Step5.2.3.3: Step5.2.3.3.1: Step5.2.3.4: Step5.2.4: Step5.3: Step6: END create empty nodes ‘ptr’, ‘nodePtr’, ‘parentPtr’ Set ptr ->info := element Set ptr -> left := ptr -> right := NULL if ( tree is NULL ) Set tree := ptr else Set parentPtr := NULL Set nodePtr := tree while ( nodePtr is NOT NULL ) Set parentPtr := nodePtr if ( element < nodePtr->info ) Set nodePtr := nodePtr -> left else Set nodePtr := nodePtr -> right End if end while end if M7.7.9: Searching an element in the Binary Search Tree (BST) : The element in a binary search tree can be searched very quickly. The search operation on binary search tree is similar to applying binary search technique to a sorted linear array. The element to be searched is compared with the root node. If it matches with the root node, then search terminates here; otherwise the search is continued in the left subtree of the node if the element is less than the root node or in the right subtree if the element is greater than the root node. The following listing shows the recursive implementation of the various steps required: BST *searchElementRecursive ( BST *tree, int value ) { if ( ( tree -> info == value ) || ( tree == NULL ) ) return tree ; else if ( value < tree->info ) return searchElementRecursive ( tree->left, value ) ; else return searchElementRecursive ( tree->right, value ) ; } Page 31 www.magix.in Algorithm for Searching an element in the binary search tree: Algorithm searchElement (Tree, value) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( ( Tree->info =value ) OR ( Tree is NULL ) ) Step2.1: return tree Step2.2: Else if ( value < Tree->info ) Step2.3: return searchElement ( tree->left, value ) Step2.4: Else Step2.5: return searchElement ( tree->right, value ) Step2.6: End if Step3: END M7.7.10: Finding the smallest element in the Binary Search Tree (BST) : Because of the order property of binary search tree, the smallest node in the tree will be one of the nodes in the left subtree, if it exists; otherwise the node itself will be the smallest node. The following listing shows the various steps required for implementation of this algo: BST *findSmallestElement ( BST *tree ) { if ( ( tree == (BST *) NULL) || (tree->left == (BST *) NULL ) ) return tree; else return findSmallestElement ( tree -> left ) ; } Algorithm for finding smallest node in the binary search tree: Algorithm findSmallest (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( ( Tree is NULL ) OR ( Tree->left is NULL) ) Step2.1: return tree Step2.2: Else Step2.3: return findSmallest ( tree -> left ) Step2.4: End if Step3: END Page 32 www.magix.in M7.7.11: Finding the largest element in the Binary Search Tree (BST) : Because of the order property of binary search tree, the largest node in the tree will be one of the nodes in the right subtree, if it exists; otherwise the node itself will be the largest node. The following listing shows the various steps required for implementation of this algorithm: BST *findLargestElement ( BST *tree ) { if ( ( tree == (BST *) NULL) || (tree->right == (BST *) NULL ) ) return tree; else return findLargestElement ( tree -> right ) ; } Algorithm for finding smallest node in the binary search tree: Algorithm findLargest (Tree) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: If ( ( Tree is NULL ) OR ( Tree->right is NULL) ) Step2.1: return tree Step2.2: Else Step2.3: return findLargest ( tree -> right ) Step2.4: End if Step3: END M7.7.12: Deleting a node from the Binary Search Tree (BST) : It is very important to remember that once the required node is found and deleted, in a binary search tree the ordering of the tree should be maintained i.e., even after deleting a node, elements in the left subtree should be lesser and elements in the right subtree should be greater than. To delete a node, the following possibilities may arise: Ø Case 1: node is terminal node – in this case, if the node is left child of its parent, then the left pointer of its parent is set to NULL; otherwise it will be right child of its parent and accordingly the pointer of its parent is set to NULL. Ø Case 2: node having only one child – In this case, the appropriate pointer of its parent is set to its child, thus by passing it. Ø Case 3: node having two children – Its predecessor replaces the node value, and then the predecessor of the node is deleted. Combining these three cases, the entire procedure for deleting a node can be implemented recursively as shown in the following listing: Page 33 www.magix.in void deleteNode ( BST **tree, int element ) { BST *temp ; if ( *tree == NULL ) { printf ( “\n Element not found” ) ; } else if ( element < (*tree)->info ) deleteNode ( & ( ( *tree ) -> left ), element ) ; else if ( element > (*tree)-> info ) deleteNode ( & ( ( *tree ) -> right ), element ) ; else if ( (*tree) -> left && ( *tree ) -> right ) { temp = findLargestNode ( ( *tree) -> left ) ; ( *tree ) -> info = temp ->info ; deleteNode ( & ((*tree) ->left) , temp->info ) ; } else { temp = *tree ; /* terminal node */ if ( ( *tree) -> left == NULL ) && ( ( *tree) -> right == NULL ) ) *tree = (BST *) NULL ; else if ( ( *tree) -> left != NULL ) /*left child only */ *tree = ( *tree) -> left ; else /* right child only */ *tree = ( *tree) -> right ; free (temp); } } Algorithm for Deleting a node: Algorithm deleteNode (Tree, element) Here TREE is a pointer contains the address of root node. Step1: Begin Step2: if ( Tree is NULL) Step2.1: Exit Step2.2: else if ( element < Treeàinfo ) Step2.2.1: deleteNode ( Treeàleft , element ) Step2.3: else if ( element > Treeàright ) Step2.3.1: deleteNode ( Treeàright , element ) Page 34 www.magix.in Step2.4: else if ( Treeàleft AND Treeàright ) Step2.4.1: temp = LargestNode ( Treeà left ) Step2.4.2: Set Treeàinfo := tempàinfo Step2.4.3: deleteNode ( Tree àleft , temp à info ) Step2.5: else Step2.5.1: Set temp := Tree Step2.5.2: if ( Treeàleft and Treeàright is NULL ) Step2.5.2.1: Set Tree := NULL Step2.5.3: else if ( Tree à left exists) Step2.5.3.1: Set Tree := Treeàleft Step2.5.4: else Step2.5.4.1: Set Tree := Treeàright Step2.5.5: end if Step2.5.6: freeNode ( temp ) Step3: end if Step4: END >> A Full length example program for tree implementation is given follows: Program to illustrate the implementation of tree using link-list : /* * Program to illustrate the implementation of different operations * discussed above on a Binary Search Tree */ #include<stdio.h> #include<conio.h> #include<alloc.h> typedef struct BST_node { struct BST_node *left ; int item ; struct BST_node *right ; } BST ; void createTree (BST **tree) { *tree = NULL ; } Page 35 www.magix.in void insertElementIterative( BST **tree , int element ) { BST *ptr, *nodePtr, *parentPtr ; ptr = (BST * ) malloc ( sizeof(BST) ) ; ptr -> item = element ; ptr -> left = ptr -> right = NULL ; if ( *tree == NULL ) *tree = ptr ; else { parentPtr = NULL ; nodePtr = *tree ; while ( nodePtr != NULL ) { parentPtr = nodePtr ; if ( element < nodePtr->item ) nodePtr = nodePtr -> left ; else nodePtr = nodePtr -> right ; } if ( element < parentPtr -> item ) parentPtr -> left = ptr ; else parentPtr -> right = ptr ; } } void preorderTraversalRecursive (BST *tree) { if(tree != NULL) { printf(" %d", tree->item ); preorderTraversalRecursive(tree->left); preorderTraversalRecursive(tree->right); } } void inorderTraversalRecursive (BST *tree) { if(tree != NULL) { inorderTraversalRecursive(tree->left); printf(" %d", tree->item); inorderTraversalRecursive(tree->right); } } Page 36 www.magix.in void postorderTraversalRecursive (BST *tree) { if(tree != NULL) { postorderTraversalRecursive(tree->left); postorderTraversalRecursive(tree->right); printf(" %d", tree->item); } } BST *searchElementRecursive ( BST *tree, int value ) { if ( ( tree -> item == value ) || ( tree == NULL ) ) return tree ; else if ( value < tree->item ) return searchElementRecursive ( tree->left, value ) ; else return searchElementRecursive ( tree->right, value ) ; } BST *findSmallestElement ( BST *tree ) { if ( ( tree == (BST *) NULL) || (tree->left == (BST *) NULL ) ) return tree; else return findSmallestElement ( tree -> left ) ; } BST *findLargestElement ( BST *tree ) { if ( ( tree == (BST *) NULL) || (tree->right == (BST *) NULL ) ) return tree; else return findLargestElement ( tree -> right ) ; } Page 37 www.magix.in void deleteNode ( BST **tree, int element ) { BST *temp ; if ( *tree == NULL ) { printf ("\n Element not found" ) ; } else if ( element < (*tree)->item ) deleteNode ( & ( ( *tree ) -> left ), element ) ; else if ( element > (*tree)-> item ) deleteNode ( & ( ( *tree ) -> right ), element ) ; else if ( (*tree) -> left && ( *tree ) -> right ) { temp = findLargestElement( (*tree)->left ) ; ( *tree ) -> item = temp ->item ; deleteNode ( & ((*tree) ->left) , temp->item ) ; } else { temp = *tree ; /* terminal node */ if ( ( *tree)->left == NULL && (*tree)-> right == NULL ) *tree = (BST *) NULL ; else if ( ( *tree) -> left != NULL ) /*left child only */ *tree = ( *tree) -> left ; else /* right child only */ *tree = ( *tree) -> right ; free (temp); } } int TotalNodes( BST *tree ) { if ( tree == NULL ) return 0 ; else return ( TotalNodes ( tree->left) + TotalNodes ( tree-> right) + 1 ) ; } int externalNodes ( BST *tree ) { if( tree== NULL ) return 0 ; else if ( ( tree->left == (BST *)NULL) && (tree->right==(BST *) NULL) ) return 1 ; else return ( externalNodes ( tree->left) + externalNodes ( tree-> right) ) ; } Page 38 www.magix.in int internalNodes ( BST *tree ) { if ( ( tree == NULL ) || ( ( tree->left == NULL) && (tree->right == NULL) ) ) return 0 ; else return ( internalNodes ( tree->left) + internalNodes ( tree-> right) + 1 ) ; } int determineHeight(BST *tree) { int leftHeight, rightHeight ; if ( tree == NULL ) return 0 ; else { leftHeight = determineHeight ( tree -> left ) ; rightHeight = determineHeight ( tree -> right ) ; if ( leftHeight > rightHeight ) return ++leftHeight ; else return ++rightHeight ; } } void removeTreeFromMemory ( BST **tree ) { if ( *tree != NULL ) { removeTreeFromMemory (& (*tree ) -> left ) ; removeTreeFromMemory (& (*tree ) -> right ) ; free( *tree ) ; } } void main (void) { int choice, element, height ; BST *root, *loc ; createTree (&root); while(1) { clrscr( ); Page 39 www.magix.in printf("\n Options available \n"); printf("++++++++++++++++++++++++++++++++\n"); printf(" 1. Insert node \n"); printf(" 2. Pre-order traversal\n"); printf(" 3. In-order traversal\n"); printf(" 4. Post-order traversal\n"); printf(" 5. Delete node\n"); printf(" 6. Total nodes\n"); printf(" 7. Total external nodes \n"); printf(" 8. Total internal nodes \n"); printf(" 9. Find height \n"); printf("10. Smallest node \n"); printf("11. Largest node \n"); printf("12. Exit\n\n"); printf("Enter your choice (1-12): "); scanf("%d",&choice); clrscr(); switch(choice) { case 1: printf("\nElement to be inserted into tree: "); scanf("%d", &element); insertElementIterative(&root, element); break; case 2: printf("\nPre-order traversal of BST is \n"); preorderTraversalRecursive(root); printf("\n\nPress any key to continue..."); getch(); break; case 3: printf("\nIn-order traversal of BST is \n"); inorderTraversalRecursive(root); printf("\n\nPress any key to continue..."); getch(); break; case 4: printf("\nPost-order traversal of BST is \n"); postorderTraversalRecursive(root); printf("\n\nPress any key to continue..."); getch(); break; Page 40 www.magix.in case 5: printf("\nElement to delete from BST is: \n"); scanf("%d", &element); deleteNode(&root, element); break; case 6: printf("\nNumber of nodes in BST is %d", TotalNodes(root)); printf("\n\nPress any key to continue..."); getch(); break; case 7: printf("\nNumber of leaf nodes in BST is %d", externalNodes(root)); printf("\n\nPress any key to continue..."); getch(); break; case 8: printf("\nNumber of non-leaf nodes in BST is %d", internalNodes(root)); printf("\n\nPress any key to continue..."); getch(); break; case 9: printf("\nHeight of BST is %d", determineHeight(root)); printf("\n\nPress any key to continue..."); getch(); break; case 10: loc = findSmallestElement(root); printf("\nSmallest node in BST is %d", loc->item); printf("\n\nPress any key to continue..."); getch(); break; case 11: loc = findLargestElement(root); printf("\nLargest node in BST is %d", loc->item); printf("\n\nPress any key to continue..."); getch(); break; case 12: removeTreeFromMemory(&root); exit(1); } } } Page 41 www.magix.in M7.8: Balanced Binary Trees: Efficiency of many important operations on trees is related to the Height of the tree – for example searching, inserting, and deleting in a BST are all O(Height). In general, the relation between Height (h) and the number of nodes (n) in a tree can vary from h=n (degenerate tree) to h = log2 n. One way to improve efficiency is to force trees to be height-balanced. A tree is perfectly height-balanced if the left and right subtrees of any node are the same height as shown in following figure: (Perfectly height balanced tree) It is clear that every level there are twice as many nodes as at the previous level, so we do indeed get h= O(log2 n). However, perfect height balance is very rare; it is only possible if there are exactly 2h-1 nodes. Balanced binary trees are classified into two categories: Ø Height Balanced tree Ø Weight Balanced tree M7.8.1: Weight Balanced Binary Trees: The nodes of a weight balanced tree contain a ‘data element’, a ‘left and right pointer’, and a ‘probability or weight field’. The data element and left and right pointers are essentially the same as any other node. The probability field is a special addition for a weight balanced tree. This field holds the probability of the node being accessed again. There are many different ways of coming up with this number. A good example of such a metric is the computing the probability according to the number of times the node has been previously searched for. When the tree is set up, the nodes with the highest probability of access are placed at the top. That way the nodes those are most likely to be accessed have the lowest search time. Page 42 www.magix.in The tree is set up with the highest weighted node at the top of the tree or subtree. The left subtree contain nodes whose data value are less than the current node, and the right subtree contains nodes that have data values greater than the current data value. (A Weight Balanced Tree) M7.8.2: Height Balanced Binary Trees/ AVL Trees: A height balanced tree is also known as AVL trees after their Russian inventors Adelson-Velskii and Landis. A tree whose subtrees differ in height by no more than one and the subtrees are height-balanced, too. An empty tree is height-balanced. An AVL tree is a special type of binary tree that is always "partially" balanced in height. In computer science, an AVL tree is a self-balancing binary search tree, and it is the first such data structure to be invented. Lookup, insertion, and deletion all take O(log2 n) time in both the average and worst cases. Additions and deletions may require the tree to be rebalanced by one or more tree rotations The “balance factor” of a node is the height of its ‘left subtree’ minus the height of its ‘right subtree’. A node with balance factor 1, 0, or -1 is considered balanced. A node with any other balance factor is considered unbalanced and requires rebalancing the tree. The balance factor is either stored directly at each node or computed from the heights of the subtrees. Page 43 www.magix.in If “T” is a nonempty binary tree with TL and TR as its left and right subtree, then T is an AVL tree if and only if: 1. |hL – hR|<= 1 , where hL and hR are the heights of TL and TR, respectively, 2. and TL and TR are also AVL trees. (Example of an AVL tree) In an AVL tree the value for ‘bf’ (Balance Factor) will be chosen as: -1 if hL < hR 0 if hL = hR +1 if hL > hR bf = If the balance factor for any node in the tree is not in between these given domain values (+1, 0, -1) then the tree is not considered as AVL tree. Insertion in AVL Tree: The INSERTION strategy is this: 1. Add the new value in the tree where it belongs (normal BST insertion). 2. Check if all subtrees are still height-balanced. If they are not, re-balance the tree by changing its shape (i.e. moving around nodes or even whole subtrees). Let's look at a simple example. Suppose we start with the empty tree. Page 44 www.magix.in Insert 3: Insert 6: Insert 2: So far things have been easy! Insert 1: Insert 0: The subtrees under ‘2’ are not height balanced. Compute the balance at each node to see this. This is the deepest `unbalanced' node. Fix it. When we have an imbalance, one of the subtrees is ‘tall’ or long the other subtree is short. To re-balance, we need to shorten the tall side and/or lengthen the short side. This can be done by what is called a rotation. In our example, ‘1’ rotates up into ‘2’s position, ‘2’ goes down on the opposite side: Page 45 www.magix.in Now the left side is 1 shorter and the right side is 1 taller. This re-balanced subtree is joined back to its place in the main tree. Continuing on, suppose we now insert -1. Computing the balance at each node, we see that everything is balanced except the top node... so we rotate the tall subtree up and the root down in the opposite direction. Page 46 www.magix.in Rotation is the operation that is used to restore balance in an AVL tree. For INSERTION, it can be shown that you never need to do more than two rotations (one rotation is not always enough) to restore balance, no matter how large the tree is. For DELETE, rotation is also used to restore balance, but in this case there are circumstances in which fixing the balance in one part of the tree creates an imbalance higher up in the tree. So, in the worst case, you might have to do O(height) rotations during a single DELETE operation. M7.9: Threaded Binary Trees: First let us see, what are the disadvantages of binary trees: Ø In a binary tree, more than 50% of link fields have NULL values and more memory space is wasted by storing NULL values. Ø Traversing a tree with binary tree is time consuming. This is because, the traversal of a tree either uses implicit stack (in case of recursive programs) or explicit stack (in case of iterative programs). Whatever it is, stack is must. Most of the time is spent in pushing and popping activities during traversing. Ø Computations of predecessor and successor of given nodes is time consuming. Ø In binary trees, only downward movement is possible. All these disadvantages can be overcome using threaded binary tree. In a binary tree, more than 50% of link fields have NULL values and more space is wasted by the presence of NULL values. These link fields which contain NULL character can be replaced by address of some nodes in the tree which facilitates upward movement in the tree. These extra links which contains addresses of some nodes (pointers) are called ‘threads’ and the tree is termed as threaded binary tree. In general, a threaded binary tree is a binary tree which contains threads (i.e., address of some nodes) which facilitates upward movement in the tree. The threads in a binary tree must be distinguished from normal pointers. In the graphical representation of a threaded binary tree, the threads are shown by dotted lines. In computer memory, an extra field, called ‘tag’ or ‘flag’ is used to distinguish a thread from a normal pointer. There are three types of threaded binary trees 1. In-threaded binary tress - In a binary tree, if LLink of any node contains NULL and if it is replaced by address of inorder predecessor, then the resulting tree is called “left inthreaded binary tree”. If Rlink of a node is null and if it is replaced by address of in-order sucessor, the resulting tree is called “Right in-threaded tree”. A “in-threaded binary tree” is one which is “both left and right inthreaded”. Page 47 www.magix.in 2. Post-threaded binary trees - In a binary tree, if LLink of any node contains NULL and if it is replaced by address of postorder predecessor, then the resulting tree is called “left post threaded binary tree”. If “Rlink” of a node is NULL and if it is replaced by address of post order sucessor, the resulting tree is called “right post threaded tree”. A “post-threaded binary” tree is one which is both “left and right post-threaded”. 3. Pre-threaded binary trees – In a binary tree, if Llink of any node contains NULL and if it is replaced by address of preorder predecessor, then the resulting tree is called “left pre threaded binary tree”. If Rlink of a node is null and if it is replaced by address of preorder sucessor, the resulting tree is called “Rightprethreaded tree”. A “Prethreaded binary tree” is one which is “both left and right pre threaded”. (An example of In-threaded Binary tree) This In-threaded binary tree is based on the in-order traversal of tree as: A B C D E F G H I Advantages of threaded binary trees – Ø In a binary tree, more than 50% of space is wasted in storing null values. This wastage of memory space is avoided by storing addresses of some nodes. Ø Traversing of a threaded binary tree is very fast. This is because, it does not use implicit or explicit stack. Page 48 www.magix.in Ø Computations of predecessor and successor of given nodes is very easy and efficient. Ø Any node can be accessed from any other node. Using threads, upward movement is possible and using links downward movement is possible. Thus, in a threaded binary tree, we can move in either direction. Ø Even though insertion into a threaded binary tree and deletion from a threaded binary tree are time consuming operations, they are very easy to implement. Disadvantages of threaded binary trees – Ø Here extra fields are required to check whether a link is a thread or not, and occupies more memory when compared to un-threaded binary trees. Ø Insertion and deletion of a node consumes more time than its counterpart, many fields have to be modified. M7.10: B- Trees: (Perfectly height balanced m-way search tree) In computer science, a B-tree is a tree data structure that keeps data sorted and allows searches, sequential access, insertions, and deletions in logarithmic time. Just as AVL trees are balanced binary search trees, B-trees are balanced M-way search trees. By imposing a balance condition, the shape of an AVL tree is constrained in a way which guarantees that the search, insertion, and withdrawal operations are all O(log2 n), where ‘n’ is the number of items in the tree. The shapes of B-Trees are constrained for the same reasons and with the same effect. A multi-way balanced tree is called as B-tree. Each node in a B-Tree contains more than one key information in an order, either in ascending or descending. B tree is not a binary tree. It grows from bottom to top rather than top to bottom. Because of the multi-ways the B-tree is also called as m-way tree. Here ‘m’ specifies the degree or order of the B-tree. In a B-tree of order ‘m’: Ø Each node has maximum of m-1 keys. Ø Each node has a maximum of ‘m’ links, means they can have maximum of ‘m’ children. Ø Each node contains keys in order. Ø All the leaves will be at the same level. Ø If a node contains m-1 keys then it is said to be full. In a full node if key is added, then the node will be split at median key value and the median will move to root or as a value in root. So, the node is split into leaves and root. Ø The insertion is always done at the leaves. Ø The siblings share the weight means they can have equal number of keys or just at the difference of 1. Page 49 www.magix.in Example of B-Tree: Following is the simple example of a B-tree of order 4 with one node containing the information 10, 15 and 20. 10 15 20 As the order is 4, the node has maximum 4-1=3 keys values and 4 links. Suppose that a key 13 is to be inserted into the B-tree. As the node is full, the node will be split at median 15 and a node with 15 becomes root. The B-tree after insertion of key 13 is: 15 10 13 20 Now suppose 9 is to be added to the B-tree. The key ‘9’ is compared with the root 15. As ‘9’ is less than ‘15’, key ‘9’ is inserted in the left node of ‘15’, before ‘10’. The Btree after insertion is: 15 9 10 13 20 Now suppose 16 and 21 are to be added to the B-Tree, then they are added in the right child of 15. The B-Tree becomes: 15 9 10 13 16 20 21 Now suppose that 8 is to be added to the B-tree. It is to be added at the left child of 15. But the node is full. So, the node will be split at median 10 and 10 will be moved to root. The B-Tree after this split operation is: 10 8 Page 50 9 13 15 16 20 21 www.magix.in The siblings of 15, left node has one key whereas right node has 3 keys. This is not permitted in B-Tree. The siblings share the weight of the tree. So, the key 15 is moved to the left node and the key 16 will be moved to the root. After these operations the B-tree will be: 10 8 9 16 13 15 20 21 Similarly if 24 is to be added it can be added in the right node of 16. The B-tree after this addition will be: 10 8 9 13 16 15 20 21 24 If the key 19 is to be added, it is supposed to be added to the right node of 16. As the node will be full after addition, the node is split at median 21 and 21 is moved to the root. So, the B-tree after this addition will be: 8 9 13 10 16 21 15 19 20 24 If the key 14 is to be added then it can be added in the left node of 16. The B-tree after this addition will be: 10 8 9 13 14 15 16 21 19 20 24 Now suppose, if a key ‘12’ is to be added to the B-tree. It is supposed to be added at the left node of ‘16’. It will be full after addition and requires a split. When the node is split then median ‘14’ moves up to root. The root will be also full and needs split. The root is split to have new root with the key ‘16’. The B-tree after this operation will be: Page 51 www.magix.in 16 10 8 9 14 12 13 21 15 19 20 24 In this way, the B-tree will grow from the leaves. The best case height of a B-Tree is: The worst case height of a B-Tree is: where m is the maximum number of children a node can have. M7.11: Heaps: A heap is a binary tree that satisfies the following properties: Ø Shape property Ø Order property By the ‘shape property’ we mean that heap must be a complete binary tree, whereas by ‘order property’ we mean that for every node in the heap, the value stored in that node is greater than or equal to the value in each of its children. A heap that satisfies these properties is known as ‘max heap’. However, if the order property is such that for every node in the heap, the value stored in that node is less than or equal to the value in each of its children, that heap is known as ‘min heap’. Example of MAX HEAP: Page 52 www.magix.in (Example of MIN HEAP) Application of heaps: Ø Sorting an array using efficient technique known as ‘heapsort’. Ø Implementing a priority queue. M7.11: Applications of Binary Trees: Some applications of binary trees are discussed follows: M7.11.1: Expression Trees: (Conversion of infix expression to prefix and postfix) The compiler uses a binary tree to represent an arithmetic expression. A binary tree can be constructed for an infix expression. When such tree is traversed using postorder it results to postfix expression. When it is traversed using pre-order traversal it results to prefix expression. These formats specify the position of a binary operator and its operands. In postfix notation, the binary operator comes after its operands, and in infix notation, the operator appears between its operands. A third notation, called ‘prefix notation, places a binary operator before its operands. The expressions in table 7.1 include each of its formats. Page 53 www.magix.in In an expression tree, each operator is an interior node whose children are operands or subexpressions. Operands are in leaf node. Assume an arithmetic expression involves the binary operators addition (+), subtraction (-), multiplication(*) and division(/). In the expression tree, each operator has two children that are either operands or subexpressions. A binary expression tree consists of: Ø Leaf node which contain a single operand. Ø Nonleaf node which contain a binary operator. Ø The left and right subtrees of an operator, describing a subexpression, which is evaluated and used as one of the operands for the operator. The trees in following figure describe the expressions in table 7.1: (Binary Expression Trees) The preorder and postorder traversal of a binary expression tree produce the prefix and postfix notation for the expression. An inorder traversal generates the infix form of the expression, assuming that parentheses are not needed to determine the order of evaluation. For instance, in above figure (c), the following are different traversals of the expression a+b*c/d-e. Preorder (prefix): -+a/*bcde Inorder (infix) a+b*c/d–e : Postorder (postfix) : Page 54 abc*d/+e www.magix.in M7.11.2: Sorting: When the binary search tree is traversed using inorder traversal technique the list can be sorted in ascending order. This is a very good application of binary tree, especially binary search tree. Let us understand with the help of following example: Sort the following list of names of the days with the help of Binary search tree (Assuming that the week starts with Monday (Mon) ) : Tue, Thu, Sat, Fri, Sun, Mon, Wed We can draw the binary search tree from the above list assuming that the week starts with ‘Mon’. When we traverse the BST in in-order traversal, we get the sorted list: Page 55 www.magix.in Now if we traverse the tree using ‘in-order’ traversal technique, we get the sorted list. In ‘in-order’ traversal technique the nodes are visited in the order Left, Root, Right. We start from the root, “Tue”. As it is not equal to NULL, we move to left. Left of node ‘Mon’ is NULL, so ‘Mon’ is processed to print out. As the right of ‘Mon’ is NULL, the information of node “Tue” is printed out. Now the Right of ‘Tue’ is processed. In the same way complete tree is traversed to get sorted list as follows: Mon, Tue, Wed, Thu, Fri, Sat, Sun M7.11.3: Heap Sorting: A complete binary tree is a special case of a binary tree, in which all the levels, except perhaps the last, are full; while on the last level, any missing nodes are to the right of all the nodes that are present. For example, we could have: (Example of complete binary tree) In a complete binary tree if every node value is greater than its left and right node values then such a complete binary tree is called as heap tree or just heap. If the node value is greater than it is called as MAX heap. In a heap the node value may be smaller than the children. If so then the heap becomes MIN heap. Such heaps can be represented very easily in memory using one dimensional array. Heaps are useful in sorting. Let us sort the following list of numbers using heap sort after constructing the heap. 42, 53, 10, 40, 92, 16, 4, 65 Initially the heap is empty. The information 42 is stored in the root of the heap: The next number 53 is inserted at the left of the node 42, to make complete binary tree. Page 56 www.magix.in The above binary tree is complete but it is not heap. We apply the process of exchanging the root with child. So, the heap will be: The next number 10 is inserted at the right of the root node 53. After insertion the binary tree is: The binary tree is complete and heap. The next number 40 is inserted into the heap as left node of node 42 in the above heap. The binary tree is: The binary tree is complete and heap. The next number 92 is inserted into the heap as right node of node 42 in the above heap. The binary tree is: The binary tree is complete but not heap. To make it heap, 92 is first exchanged with 42, then with 53. So, 92 becomes root of the heap. After exchanges the heap will be: Page 57 www.magix.in The next number 16 is inserted as left node of node 10. The binary tree is complete but not heap. So, it is heapified by exchanging 16 with its root 10. Both the trees are as follows: The next number 4 is inserted as right node of node 16. The tree is as follows and it is heap. The next number 65 is inserted as left node 40 in the above heap. The tree is: Page 58 www.magix.in The binary tree is complete but not heap. To make it heap, 65 is first exchanged with 40, then with 53. So, 65 becomes left child of root and root of the children 53 and 42. The heap obtained after these exchanges will be the final heap because the list is complete. The final heap is: The process of creating heap is over. Now to sort the numbers we require an array of size 8. The heap always contains the largest element as the root. So, to sort the numbers the root of the heap is always deleted and added to the respective position in the array from the last position. After the deletion of root from the heap, the heap is adjusted to make it complete binary tree as well as heap. Step by step the procedure is explained below: The root 92 is deleted from the heap and added to the array at 8th position. The array will be: To obtain the heap after deletion of root 92, one of its children that is largest is moved up as root. In this case 65 becomes root of the heap. Node 53 takes place of node 65 and node 40 takes the place of node 53. The heap obtained after these operations is: Page 59 www.magix.in The root 65 is deleted from the heap and added to the array at 7th position. The array will be: To obtain the heap after deletion of root 65, one of its children that is largest is moved up as root. In this case 53 becomes root of the heap. So, node 53 takes the place of node 65 and node 42 takes place of node 53. The tree obtained after these operations is: The above binary tree is not complete binary tree so it is not heap. To make the binary tree complete, the last node 4 is placed as the right node of node 42. The tree becomes complete and it is heap. So, the heap is: The root 53 is deleted from the heap and added to the array at 6th position. The array will be: Page 60 www.magix.in To obtain the heap after deletion of root 53, one of its children that is largest is moved up as root. In this case 42 becomes root of the heap. So, node 42 takes the place of node 53. One of the children of node 42, the one which is largest will become the root of that sub tree. So, node 40 takes the place of node 42. The tree obtained after these operations is: The above binary tree is not complete binary tree so it is not heap. To make it complete the last node 10 is placed as the left node of node 40. The tree becomes complete and it is heap. So, the heap is: The root 42 is deleted from the heap and added to the array at 5th position. The array will be: To obtain the heap after deletion of root 42, one of its children that is largest is moved up as root. In this case 40 becomes root of the heap. So, node 40 takes the place of node 42. Node 10 takes the place of node 40. The tree obtained after these operation is: Page 61 www.magix.in The binary tree obtained is not complete binary tree so it is not heap. To make the binary tree complete the last node 4 is placed as the left node of node 10. The tree becomes complete and it is heap. So, the heap is: The root 40 is deleted from the heap and added to the array at 4th position. The array will be: To obtain the heap after deletion of root 40, one of its children that is largest is moved up as root. In this case 16 becomes root of the heap. So, node 16 takes the place of node 40. The node 4 takes the place of node 16, to make the binary tree as heap. The tree obtained after these operations is: The above binary tree is complete and it is also heap. The root 16 is deleted from the heap and added to the array at 3rd position. The array will be: To obtain the heap after deletion of root 16, one of its children that is largest is moved up as root. In this case 10 becomes root of the heap. So, node 10 takes the place of node 16. Similarly node 4 takes the place of node 10. After the operations the heap will be: Page 62 www.magix.in The root 10 is deleted from the heap and added to the array at 2nd position. The array will be: After the operation node 4 will move up and takes the place of 10. The heap contains only node 4. It is deleted and added to the array at 1st position. The sorted array will be: Page 63 www.magix.in