threaded binary tree

36
THREADED BINARY TREE Consider the linked representation of a binary tree T, approximately half of the entries in left pointer field and right pointer field contains NULL elements. This space occupied by NULL entries can be efficiently utilized to store some kind of valuable information. These special pointers are called threads, and the binary tree having such pointers is called a threaded binary tree. Threads in a binary tree are represented by a dotted line. There are many ways to thread a binary tree these are— 1. The right NULL pointer of each leaf node can be replaced by a thread to the successor of that node under in order traversal called a right thread, and the tree will called a right threaded tree or right threaded binary tree. 2. The left NULL pointer of each node can be replaced by a thread to the predecessor of that node under in order traversal called left thread, and the tree will called a left threaded tree. 3. Both left and right NULL pointers can be used to point to predecessor and successor of that node respectively, under in order traversal. Such a tree is called a fully threaded tree.

Upload: pramodsoni0007

Post on 23-Oct-2014

411 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Threaded Binary Tree

THREADED BINARY TREE

Consider the linked representation of a binary tree T, approximately half of the entries in

left pointer field and right pointer field contains NULL elements. This space occupied by

NULL entries can be efficiently utilized to store some kind of valuable information.

These special pointers are called threads, and the binary tree having such pointers is

called a threaded binary tree. 

Threads in a binary tree are represented by a dotted line. There are many ways to thread a

binary tree these are— 

1. The right NULL pointer of each leaf node can be replaced by a thread to the

successor of that node under in order traversal called a right thread, and the tree

will called a right threaded tree or right threaded binary tree. 

2. The left NULL pointer of each node can be replaced by a thread to the

predecessor of that node under in order traversal called left thread, and the tree

will called a left threaded tree.

3. Both left and right NULL pointers can be used to point to predecessor and

successor of that node respectively, under in order traversal. Such a tree is called a

fully threaded tree.

A threaded binary tree where only one thread is used is also known as one way threaded

tree and where both threads are used is also known as two way threaded tree.

Page 2: Threaded Binary Tree

Memory Representatin Of Treaded Binayr Tree

In above representation char thread field is as a tag. It will hold 0 for normal right pointer

and 1 for thread.

Page 3: Threaded Binary Tree

1

TreesExamples of Tree structureDefinition of treesBinary treeHeight of treeTree traversalsFinding maxFinding sum2

TreesYou have seen that using linked lists you canrepresent an ordered collection of values withoutusing arrays. Although linked lists require morememory space than arrays ( as they have to storeaddress at each node), they have definite advantagesover arrays. Insertion and deletion of items can becarried out with out involving considerablemovement of data.The ordering relationship amongst a set of values isobtained through use of pointers. However, we neednot restrict ourselves to only linear structures. In thischapter we shall extend the use of pointers to define a

Page 4: Threaded Binary Tree

non-linear structure to model hierarchicalrelationships, such as a family tree.In such a tree, we have links moving from anancestor to a parent, and links moving from theparent to children. We have many other examples oftree-structured hierarchies.Directory Hierarchies: In computers, files are storedin directories that form a tree. The top level directoryrepresents the root. It has many subdirectories and3

files. The subdirectories would have further set ofsubdirectories.Organization charts: In a company a number of vicepresidents report to a president. Each VP would havea set of general managers, each GM having his/herown set of specific managers and so on.Biological classifications: Starting from living beingat the root, such a tree can branch off to mammals,birds, marine life etc.Game Trees: All games which require only mentaleffort would always have number of possible optionsat any position of the game. For each position, therewould be number of counter moves. The repetitivepattern results in what is known a game tree.Tree as a data structure• A tree is a data structure that is made of nodes andpointers, much like a linked list. The differencebetween them lies in how they are organized:

Page 5: Threaded Binary Tree

• The top node in the tree is called the root and allother nodes branch off from this one.4

• Every node in the tree can have some number ofchildren. Each child node can in turn be the parentnode to its children and so on.• Child nodes can have links only from a singleparent.• Any node higher up than the parent is called anancestor node.• Nodes having no children are called leaves.• Any node which is neither a root, nor a leaf iscalled an interior node.• The height of a tree is defined to be the length ofthe longest path from the root to a leaf in that tree( including the path to root)• A common example of a tree structure is the binarytree.Binary Trees5

Definition: A binary tree is a tree in which eachnode can have maximum two children. Thus eachnode can have no child, one child or two children.The pointers help us to identify whether it is a leftchild or a right child.Application of a Binary treeBefore we define any formal algorithms, let us lookat one possible application of a binary tree.

Page 6: Threaded Binary Tree

Consider a set of numbers: 25,63,13, 72,18,32,59,67.Suppose we store these numbers in individual nodesof a singly linked list. To search for a particular itemwe have to go through the list, and maybe we have togo to the end of the list as well. Thus if there were nnumbers, our search complexity would be O(n).Is it because the numbers are not in any particularsequence? Now suppose we order these numbers:13,18,25,32,59,63,67,72. and store these in anotherlinked list.What would be the search complexity now? You maybe surprised to discover that it is still O(n). Yousimply cannot apply binary search on a linked listwith O(log n) complexity. You still have to go6

through each link to locate a particular number. So alinear linked structure is not helping us at all.Let us see if we can improve the situation by storingthe data using a binary tree structure. Consider thefollowing binary tree where the numbers have beenstored in a specific order. The value at any node ismore than the values stored in the left-child nodes,and less than the values stored in the right-childnodes.5918 6713 32 63 72257

Page 7: Threaded Binary Tree

With this arrangement any search is taking at most 4steps.For larger set of numbers, if we can come up with agood tree arrangement than the search time can bereduced dramatically.Examples of binary trees:root root8

• The following are NOT binary trees:9

Definitions:• tree, then n1 is the parent of n2 and n2 is the left orright child of n1.• The level of a node in a binary tree:- The root of the tree has level 0- The level of any other node in the tree is one morethan the level of its parent.root Level 0Level 1Level 2Level 310

Full Binary TreeHow many nodes?Level 0 : 1 node ( height 1)Level 1: 2 nodes ( height 2)Level 3 : 4 nodes (height 3)Level 3: 8 nodes (height 4)Total number of nodesn = 2h – 1 ( maximum)h = log ( n+1)

Page 8: Threaded Binary Tree

4524 7614 32 61 878 20 27 3756 6781 9411

Implementation• A binary tree has a natural implementation in linkedstorage. A tree is referenced with a pointer to its root.• Recursive definition of a binary tree:A binary tree is either- Empty, or- A node (called root) together with two binary trees(called left subtree and the right subtree of the root)• Each node of a binary tree has both left and rightsubtrees which can be reached with pointers:struct tree_node{int data;struct tree_node *left_child;struct tree_node *right_child;};left_child data right_child12

Note the recursive definition of trees. A tree is a node withstructure that contains more trees. We have actually a treelocated at each node of a tree.Traversal of Binary TreesLinked lists are traversed sequentially from first node to the

Page 9: Threaded Binary Tree

last node. However, there is no such natural linear order forthe nodes of a tree. Different orderings are possible fortraversing a binary tree. Every node in the tree is a root forthe subtree that it points to. There are three commontraversals for binary trees:• Preorder• Inorder• PostorderThese names are chosen according to the sequence inwhich the root node and its children are visited.Suppose there are only 3 nodes in the tree having thefollowing arrangement:13

− With inorder traversal the order is left-child, root node,right-child− With preorder traversal the order is root node, leftchild , right child.− With postorder traversal the order is left child, rightchild, root node.

n1n2 n3In – order : n2 n1 n3Pre-order : n1 n2 n3Post order : n2 n3 n114

A tree will typically have more than 3 nodes. Instead ofnodes n2 and n3 there would be subtrees as shown below:− With inorder traversal the order is left subtree, then theroot and finally the right subtree. Thus the root is visitedin-between visiting the left and right subtrees.

Page 10: Threaded Binary Tree

− With preorder traversal the root node is visited first,then the nodes in the left subtree are visited followed bythe nodes in the right subtrees

rootLeftsubtreeRightsubtree15

− With postorder traversal the root is visited after both thesubtrees have been visited.(left subtree followed by rightsubtree.• As the structure of a binary tree is recursive, the traversalalgorithms are inherently recursive.Algorithm for Preorder traversalIn a preorder traversal, we first visit the root node.If there is a left child we visit the left subtree (all thenodes) in pre-order fashion starting with that left child .If there is a right child then we visit the right subtree inpre-order fashion starting with that right child.The function may seem very simplistic, but the real powerlies in the recursive formulation. In fact there is a doublerecursion. The real job is done by the system on the runtimestack. This simplifies coding while it puts a heavyburden on the system.void preorder(struct tree_node * p){ if (p !=NULL) {printf(“%d\n”, p->data);16

preorder(p->left_child);

Page 11: Threaded Binary Tree

preorder(p->right_child);}}Take a tree of say height 3 with maybe 6 nodes and try torun the above recursion to find out the actual order ofprinting the nodes.Example:Preorder Traversal : a b c d f g ea(root)b(left)c d f g e (right)Algorithm for Inorder traversalroot ab cd ef g17

In the inorder traversal, we first visit its left subtree (all thenodes) , then we visit the root node and then its rightsubtree.void inorder(struct tree_node *p){ if (p !=NULL) {inorder(p->left_child);printf(“%d\n”, p->data);inorder(p->right_child);}}Inorder: b a f d g c eb(left)a(root)f d g c e(right)Algorithm for Postorder traversal

Page 12: Threaded Binary Tree

root ab cd ef g18

In a postorder traversal, we first visit its left subtree (all thenodes) and then visit its right subtree ( all the nodes) andthen finally we visit the root node.void postorder(struct tree_node *p){ if (p !=NULL) {postorder(p->left_child);postorder(p->right_child);printf(“%d\n”, p->data);}}Example:Postorder: b f g d e c ab(left)root ab cd ef g19

f g d e c(right)a(root)20

Finding Maximum value in a given tree pint findMax (struct tree_node *p){int node_data, leftmax, rightmax, max;max = -1//assume all values in the tree are positiveintegersif (p != NULL){ node_data = p -> data;

Page 13: Threaded Binary Tree

leftmax = findMax(p -> left_child);rightmax = findMax(p->right_child);//find the largest of the tree values.if (leftmax > rightmax)max = leftmax;elsemax = rightmax;if (node_data > max)max = node_data;}return max;21

node_value = 45leftmax = 24 (max of 24, -1, -1 )rightmax = 76 (max of 76, -1, -1 )max = max of 45, 24, 76= 7624457622

max of left subtreeleftmax = max ( 24,12,32)= 24rightmax = 76max of tree = max (45, leftmax, rightmax)= 7624 7614 3245

Page 14: Threaded Binary Tree

23

Finding sum of values of all the nodes of a treeTo find the sum, add to the value of the current node, thesum of values of all nodes of left subtree and the sum ofvalues of all nodes in right subtree.int sum(struct tree_node *p){if ( p!= NULL)return(p->data + sum(p->left_child)+ sum(p->right_child));elsereturn 0;}24

Page 15: Threaded Binary Tree

AVL Trees

The Concept

These are self-adjusting, height-balanced binary search trees and are named after the inventors: Adelson-Velskii and Landis. A balanced binary search tree has Theta(lg n) height and hence Theta(lg n) worst case lookup and insertion times. However, ordinary binary search trees have a bad worst case. When sorted data is inserted, the binary search tree is very unbalanced, essentially more of a linear list, with Theta(n) height and thus Theta(n) worst case insertion and lookup times. AVL trees overcome this problem.

Definitions

The height of a binary tree is the maximum path length from the root to a leaf. A single-node binary tree has height 0, and an empty binary tree has height -1. As another example, the following binary tree has height 3.

7

/ \

3 12

/ / \

2 10 20

/ \

9 11

An AVL tree is a binary search tree in which every node is height balanced, that is, the difference in the heights of its two subtrees is at most 1. The balance factor of a node is the height of its right subtree minus the height of its left subtree. An equivalent definition, then, for an AVL tree is that it is a binary search tree in which each node has a balance factor of -1, 0, or +1. Note that a balance factor of -1 means that the subtree is left-heavy, and a balance factor of +1 means that the subtree is right-heavy. For example, in the following AVL tree, note that the root node with balance factor +1 has a right subtree of height 1 more than the height of the left subtree. (The balance factors are shown at the top of each node.)

+1 30

/ \

Page 16: Threaded Binary Tree

-1 0 22 62

/ / \

0 +1 -1 5 44 95

\ / 0 0 51 77

The idea is that an AVL tree is close to being completely balanced. Hence it should have Theta(lg n) height (it does - always) and so have Theta(lg n) worst case insertion and lookup times. An AVL tree does not have a bad worst case, like a binary search tree which can become very unbalanced and give Theta(n) worst case lookup and insertion times. The following binary search tree is not an AVL tree. Notice the balance factor of -2 at node 70.

-1 100

/ \

-2 -1 70 150 / \ / \

+1 0 +1 0 30 80 130 180

/ \ \ 0 -1 0 10 40 140 / 0 36

Inserting a New Item

Initially, a new item is inserted just as in a binary search tree. Note that the item always goes into a new leaf. The tree is then readjusted as needed in order to maintain it as an AVL tree. There are three main cases to consider when inserting a new node.

Case 1:

A node with balance factor 0 changes to +1 or -1 when a new node is inserted below it. No change is needed at this node. Consider the following example. Note that after an insertion one only needs to check the balances along the path from the new leaf to the root.

Page 17: Threaded Binary Tree

0 40

/ \

+1 0 20 50

\ / \

0 0 0 30 45 70

After inserting 60 we get:

+1 40

/ \

+1 +1 20 50

\ / \

0 0 -1 30 45 70 / 0 60

Case 2:

A node with balance factor -1 changes to 0 when a new node is inserted in its right subtree. (Similarly for +1 changing to 0 when inserting in the left subtree.) No change is needed at this node. Consider the following example.

-1 40

/ \

+1 0 20 50

/ \ / \

0 0 0 0 10 30 45 70 / \ 0 0 22 32

Page 18: Threaded Binary Tree

After inserting 60 we get:

0 <-- the -1 changed to a 0 (case 2) 40

/ \

+1 +1 <-- an example of case 1 20 50

/ \ / \

0 0 0 -1 <-- an example of case 1 10 30 45 70 / \ / 0 0 0 22 32 60

Case 3:

A node with balance factor -1 changes to -2 when a new node is inserted in its left subtree. (Similarly for +1 changing to +2 when inserting in the right subtree.) Change is needed at this node. The tree is restored to an AVL tree by using a rotation.

Subcase A:

This consists of the following situation, where P denotes the parent of the subtree being examined, LC is P's left child, and X is the new node added. Note that inserting X makes P have a balance factor of -2 and LC have a balance factor of -1. The -2 must be fixed. This is accomplished by doing a right rotation at P. Note that rotations do not mess up the order of the nodes given in an inorder traversal. This is very important since it means that we still have a legitimate binary search tree. (Note, too, that the mirror image situation is also included under subcase A.)

(rest of tree) | -2 P

/ \

-1 sub LC tree of / \ height n sub sub tree tree of of height height

Page 19: Threaded Binary Tree

n n / X

The fix is to use a single right rotation at node P. (In the mirror image case a single left rotation is used at P.) This gives the following picture.

(rest of tree) | 0 LC

/ \

sub P tree of / \ height n sub sub / tree tree X of of height height n n

Consider the following more detailed example that illustrates subcase A.

-1 80

/ \

-1 -1 30 100

/ \ /

0 0 0 15 40 90 / \ 0 0 10 20

We then insert 5 and then check the balance factors from the new leaf up toward the root. (Always check from the bottom up.)

-2 80

/ \

-2 -1 30 100

Page 20: Threaded Binary Tree

/ \ /

-1 0 0 15 40 90 / \ -1 0 10 20 / 0 5

This reveals a balance factor of -2 at node 30 that must be fixed. (Since we work bottom up, we reach the -2 at 30 first. The other -2 problem will go away once we fix the problem at 30.) The fix is accomplished with a right rotation at node 30, leading to the following picture.

-1 80

/ \

0 -1 15 100

/ \ /

-1 0 0 10 30 90 / / \ 0 0 0 5 20 40

Recall that the mirror image situation is also included under subcase A. The following is a general illustration of this situation. The fix is to use a single left rotation at P. See if you can draw a picture of the following after the left rotation at P. Then draw a picture of a particular example that fits our general picture below and fix it with a left rotation.

(rest of tree) | +2 P

/ \

sub +1 tree RC of height / \ n sub sub tree tree of of height height n n

Page 21: Threaded Binary Tree

\ X

Subcase B:

This consists of the following situation, where P denotes the parent of the subtree being examined, LC is P's left child, NP is the node that will be the new parent, and X is the new node added. X might be added to either of the subtrees of height n-1. Note that inserting X makes P have a balance factor of -2 and LC have a balance factor of +1. The -2 must be fixed. This is accomplished by doing a double rotation at P (explained below). (Note that the mirror image situation is also included under subcase B.)

(rest of tree) | -2 P

/ \

+1 sub LC tree of / \ height n sub -1 tree NP of / \ height sub sub n tree tree n-1 n-1 / X

The fix is to use a double right rotation at node P. A double right rotation at P consists of a single left rotation at LC followed by a single right rotation at P. (In the mirror image case a double left rotation is used at P. This consists of a single right rotation at the right child RC followed by a single left rotation at P.) In the above picture, the double rotation gives the following (where we first show the result of the left rotation at LC, then a new picture for the result of the right rotation at P).

(rest of tree) | -2 P

/ \

-2 sub NP tree of / \ height n 0 sub

Page 22: Threaded Binary Tree

LC tree / \ n-1 sub sub tree tree of n-1 height / n X

Finally we have the following picture after doing the right rotation at P.

(rest of tree) | 0 NP

/ \

0 +1 LC P / \ / \ sub sub sub sub tree tree tree tree of n-1 n-1 of height / height n X n

Consider the following concrete example of subcase B.

-1 80

/ \

0 0 30 100

/ \ / \

-1 0 0 0 20 50 90 120 / / \ 0 0 0 10 40 60

After inserting 55, we get a problem, a balance factor of -2 at the root node, as seen below.

-2 80

/ \

Page 23: Threaded Binary Tree

+1 0 30 100

/ \ / \

-1 +1 0 0 20 50 90 120 / / \ 0 0 -1 10 40 60 / 0 55

As discussed above, this calls for a double rotation. First we do a single left rotation at 30. This gives the following picture.

-2 80

/ \

-1 0 50 100

/ \ / \

-1 -1 0 0 30 60 90 120 / \ / -1 0 0 20 40 55 / 0 10

Finally, the right rotation at 80 restores the binary search tree to be an AVL tree. The resulting picture is shown below.

0 50

/ \

-1 0 30 80

/ \ / \

-1 0 -1 0 20 40 60 100 / / / \ 0 0 0 0 10 55 90 120

Page 24: Threaded Binary Tree

Example Program

itemtype.h bstnode.h bstnode.cpp bstree.h bstree.cpp avlnode.h avlnode.cpp avltree.h avltree.cpp avltest.cpp

This example program inserts some characters into an AVL tree, uses a print routine to see that the AVL tree is correct, and tries out other features such as the copy constructor, the Find function, etc.

The class AVLClass is derived by public inheritance from the class BSTClass. Since we have already implemented binary search trees and AVL trees are a form of specialized binary search tree, this allows considerable code reuse. The public functions provided are a constructor, a copy constructor, a destructor, an overloaded assignment operator, and a function to insert a new item. The following public functions are inherited from BSTClass and hence are also available: NumItems, Empty, Find, and Print. AVLClass also has numerous private functions to carry out the various rotations and the like.

Note that the Print function prints the binary search tree sideways, as it is much easier to do so. Note, too, that AVLClass is named as a friend of BSTClass so that it can have direct access to the private data fields of the latter class. This makes the coding simpler. There are no new data fields added in the derived class.

AVLNodeClass is derived by public inheritance from BSTNodeClass. In the BSTNodeClass note that the data fields are protected fields, instead of the usual private fields. (Public fields are also possible but rarely used since they violate the principle of information hiding.) A protected field is directly accessible in a publicly derived class, but is not accessible elsewhere, such as from our application program in the main function. This means that we do not need to make AVLNodeClass a friend of BSTNodeClass in order for the derived class to have direct access to the data fields. The AVLNodeClass only needs to add one data field to the inherited ones: a field to hold the balance number for this node.

One messy feature of the above example is that in many places a cast is required so that a pointer to a BSTNodeClass node is seen as a pointer to an AVLNodeClass node. For example, the CopySubtree function in AVLClass contains:

NewLeftPtr = CopySubtree(reinterpret_cast <AVLNodePtr> (Current->Left))

Page 25: Threaded Binary Tree

This is needed because the data field Left is a pointer to the wrong type of node, a BSTNodeClass node. Since CopySubtree expects a pointer to an AVLNodeClass node, we need the cast. One type of node is derived by inheritance from the other and is almost the same, but to the compiler they are different types. So a pointer to one type of node is not of the same type as a pointer to the other type of node. Hence we need the cast. Similar casts occur in the application code found in the main function, such as:

Result = reinterpret_cast <AVLNodePtr> (AVLTreeA.Find('E'))

This one is needed since we are using the inherited Find function on an AVL tree, which belongs to the derived class. Our Find function returns a pointer to the wrong type of node, so we fix it up with the cast. Code reuse helps a lot, but here it does add the nuisance of a cast.