1.14k likes | 1.16k Views
Understand the terminology, properties, and representations of trees, including binary trees, with clear examples and practical insights for algorithms. Learn about nodes, levels, heights, and more!
E N D
5.1 Introduction 5.1.1 Terminology • Tree : a finite set of one or more nodes • there is a specially designated node called the root • the remaining nodes are partitioned into n 0 disjoint sets T1, ..., Tn, where each of these sets is a tree. T1, ..., Tn are called the subtrees of the root. • Degree of a node : the number of subtrees of a node • Leaf (terminal node) : a node that has degree zero • Nonterminals : the other nodes • Children, parent, siblings • Degree of a tree : the maximum of degree of the nodes in the tree
5.1 Introduction(Cont’) • Ancestors of a node : all the nodes along the path from the root to that node • Level of a node : the distance from the root+1 • Height (or depth) of a tree : the maximum level of any node in the tree
5.1 Introduction(Cont’) Figure 5.1 : Two types of genealogical charts
A B C D E F G H I J K L M 5.1 Introduction(Cont’) Figure 5.2 : A sample tree
5.1 Introduction(Cont’) 5.1.2 Representation of Trees • List representation • the tree of Figure 5.2 (A(B(E(K,L),F),C(G),D(H(M),I,J))) • the degree of each node may be different • possible to use memory nodes with a varying number of pointer fields • easier to write algorithms when the node size is fixed • nodes of a fixed size • for a tree of degree k • Lemma : If T is a k-ary tree with n nodes, each having a fixed size, then n(k-1)+1 of the nk child fields are 0, n 1
A 0 B F 0 C G 0 D I J 0 E K L 0 H M 0 5.1 Introduction(Cont’) Figure 5.3 : List representation of the tree of Figure 5.2
A B D C E F G H J I K L M 5.1 Introduction(Cont’) • Left child-right sibling representation • node structure • the left child field of each node points to its leftmost child (if any), and the right sibling field points to its closest right sibling (if any) Figure 5.6 : Left child-right sibling representation of the tree of Figure 5.2
A B A C E B B K D F G L H M I J 5.1 Introduction(Cont’) • Representation as a degree-two tree • rotate the right-sibling pointers clockwise by 45 degrees • the two children of a node are referred to as the left and right children Figure 5.7 : Left child-right child tree representation
A A A B B B A B C A A B C B C 5.1 Introduction(Cont’) • additional examples Figure 5.8 : Tree representations • left child-right child tree : binary tree • any tree can be represented as a binary tree
A A B B 5.2 Binary Trees 5.2.1 The Abstract Data Type • A binary tree a finite set of nodes that either is empty or consists of a root and two disjoint binary trees called the left subtree and the right subtree • Differences between a binary tree and a tree • there is an empty binary tree • the order of the children is distinguished in a binary tree • Complete binary tree and Full binary tree (Fig. 5.10, Fig. 5.11) Figure 5.9 : Two different binary trees
5.2 Binary Trees(Cont’) template <class KeyType> class BinaryTree { // objects: A finite set of nodes either empty or consisting of a root // node, left BinaryTree and right BinaryTree. public: BinaryTree(); // creates an empty binary tree Boolean IsEmpty(); // if the binary tree is empty, return TRUE (1); else return // FALSE (0) BinaryTree(BinaryTree bt 1, Element<KeyType> item, BinaryTree bt 2); // creates a binary tree whose left subtree is bt 1, whose right // subtree is bt 2, and whose root node contains item
5.2 Binary Trees(Cont’) • BinaryTree Lchild(); • // if IsEmpty(), return error; else return the left subtree of *this • Element<KeyType> Data(); • // if IsEmpty(), return error; else return the data • // in the root node of *this • BinaryTree Rchild(); • // if IsEmpty(), return error; else return the right subtree of *this • }; ADT 5.1 : Abstract data type BinaryTree
A A B B C C D G E F D H I E 5.2 Binary Trees(Cont’) Figure 5.10 : Skewed and complete binary trees
5.2 Binary Trees(Cont’) 5.2.2 Properties of Binary Trees • Lemma 5.2 [Maximum number of nodes] (1) The max number of nodes on level i of a binary tree is 2i-1, i≥ 1 (2) The max number of nodes in a binary tree of depth k is 2k-1, k≤ 1 • Lemma 5.3 [Relation between number of leaf nodes and degree-2 nodes] For any non-empty binary tree, T, if n0 is the number of leaf nodes and n2 the number of nodes of degree 2, then n0=n2+1 • A full binary tree of depth k • a binary tree of depth k having 2k-1 nodes, k≥ 0
5.2 Binary Trees(Cont’) 1 2 3 4 5 6 7 10 11 13 8 9 12 14 15 Figure 5.11 : Full binary tree of depth 4 with sequential node numbers
5.2 Binary Trees(Cont’) • A binary tree with n nodes and depth k is complete • its nodes correspond to the nodes numbered from 1 to n in the full binary tree of depth k • The height of a complete binary tree with n nodes is
5.2 Binary Trees(Cont’) 5.2.3 Binary Tree Representation • Array representation • Lemma 5.4 : If a complete binary tree with n nodes is represented sequentially, then for any node with index i, 1≤ i≤ n, we have (1) parent(i) is at if i ≠1. If i=1, i is at the root and has no parent (2) LeftChild(i) is at 2i if 2i≤ n. If 2i>n, then i has no left child (3) RightChild(i) is at 2i+1 if 2i+1≤ n. If 2i+1>n, then i has no right child
5.2 Binary Trees(Cont’) Figure 5.12 : Array representation of the binary trees of Figure 5.10
5.2 Binary Trees(Cont’) • Linked representation • classes to define a tree class Tree; //forward declaration class TreeNode { friend class Tree; private: TreeNode *LeftChild; char data; TreeNode *RightChild; }; class Tree { public: // Tree operations ... private: TreeNode *root; };
5.2 Binary Trees(Cont’) data Figure 5.13 : Node representations
A B C D E 5.2 Binary Trees(Cont’)
A B C D G E F H I 5.2 Binary Trees(Cont’) Figure 5.14 : Linked representation for the binary trees of Figure 5.10
A B D C E 5.2 Binary Trees(Cont’) Figure 5.15 : Binary tree for Exercise 1
5.3 Binary Tree Traversal and TreeIterators 5.3.1 Introduction • Tree traversal • visiting each node in the tree exactly once • a full traversal produces a linear order for the nodes • Order of node visit L : move left V : visit node R : move right • possible combinations : LVR, LRV, VLR, VRL, RVL, RLV • traverse left before right • LVR : inorder • LRV : postorder • VLR : preorder
5.3 Binary Tree Traversal and Tree Iterators(Cont’) + * E * D C / B A Figure 5.16 : Binary tree with arithmetic expression
5.3 Binary Tree Traversal and Tree Iterators(Cont’) 5.3.2 Inorder Traversal • LVR void Tree::inorder() // Driver call workhorse for traversal of entire tree. The driver is // declared as a public member function of Tree. { inorder(root); } void Tree::inorder(TreeNode *CurrentNode) // Workhorse traverses the subtree rooted at CurrentNode (which is // a pointer to a node in a binary tree). The workhorse is declared // as a private member function of Tree. { if (CurrentNode) { inorder(CurrentNode->LeftChild); cout << CurrentNode->data; inorder(CurrentNode->RightChild); } } Program 5.1 : Inorder traversal of a binary tree
5.3 Binary Tree Traversal and Tree Iterators(Cont’) Figure 5.17 : Trace of Program 5.1
5.3 Binary Tree Traversal and Tree Iterators(Cont’) • Output : A/B*C*D+E • infix form of the expression
5.3 Binary Tree Traversal and Tree Iterators(Cont’) 5.3.3 Preorder Traversal • VLR void Tree::preorder() { // Driver calls workhorse for traversal of entire tree. The driver is // declared as a public member function of Tree. preorder(root); } void Tree::preorder(TreeNode *CurrentNode) // Workhorse traverses the subtree rooted at CurrentNode (which is // a pointer to a node in a binary tree). The workhorse is declared // as a private member function of Tree. { if (CurrentNode) { cout << CurrentNode->data; preorder(CurrentNode->LeftChild); preorder(CurrentNode->RightChild); } } Program 5.2 : Preorder traversal of a binary tree
5.3 Binary Tree Traversal and Tree Iterators(Cont’) • Output : +**/ABCDE • prefix form of the expression
5.3 Binary Tree Traversal and Tree Iterators(Cont’) 5.3.4 Postorder Traversal • LRV void Tree::postorder() { // Driver calls workhorse for traversal of entire tree. The // driver is declared as a public member function of Tree. postorder(root); } void Tree::postorder(TreeNode *CurrentNode) // Workhorse traverses the subtree rooted at // CurrentNode (which is a pointer to a node in a binary tree). // The workhorse is declared as a private member function of Tree { if (CurrentNode) { postorder(CurrentNode->LeftChild); postorder(CurrentNode->RightChild); cout << CurrentNode->data; } } Program 5.3 : Postorder traversal of a binary tree
5.3 Binary Tree Traversal and Tree Iterators(Cont’) • Output : AB/C*D*E+ • postfix form of the expression
5.3 Binary Tree Traversal and Tree Iterators(Cont’) 5.3.5 Iterative Inorder Traversal • Tree is a container class • may implement a tree traversal algorithm by using iterators • the algorithm needs to be non-recursive • use template Stack class • Definition • a data object of Type A USES-A data object of Type B if a Type A object uses a Type B object to perform a task • this relationship is typically expressed by employing the Type B object in a member function of Type A
5.3 Binary Tree Traversal and Tree Iterators(Cont’) void Tree::NonrecInorder() // nonrecursive inorder traversal using a stack { Stack<TreeNode *> s; // declare and initialize stack TreeNode *CurrentNode = root; while(1) { while(CurrentNode){ // move down LeftChild fields s.add(CurrentNode); // add to stack CurrentNode = CurrentNode->LeftChild; } if (!s.IsEmpty()) { // stack is not empty CurrentNode = *s.Delete(CurrentNode); // delete from stack cout << CurrentNode->data << endl; CurrentNode = CurrentNode->RightChild; } else break; } } Program 5.4 : Nonrecursive inorder traversal
5.3 Binary Tree Traversal and Tree Iterators(Cont’) • Iteration • each iteration of the while loop (lines 6-17) yields the next element in the inorder traversal class InorderIterator { public: char *Next(); InorderIterator(Tree tree) : t(tree) {CurrentNode = t.root;}; private: Tree t; Stack <TreeNode *> s; TreeNode *CurrentNode; }; Program 5.5 : Definition of inorder iterator class
5.3 Binary Tree Traversal and Tree Iterators(Cont’) char *InorderIterator::Next() { while(CurrentNode) { s.add(CurrentNode); CurrentNode = CurrentNode->LeftChild; } if (!s.IsEmpty()) { CurrentNode = *s.Delete(CurrentNode); char &temp = CurrentNode->data; CurrentNode = CurrentNode->RightChild; //update CurrentNode return &temp; } else return 0; // tree has been traversed. no more elements } Program 5.6 : Code for obtaining the next inorder element
5.3 Binary Tree Traversal and Tree Iterators(Cont’) 5.3.6 Level-Order Traversal • Root-left child-right child • requires a queue void Tree::LevelOrder() // Traverse the binary tree in level order { QUEUE<TreeNode*> q; TreeNode *CurrentNode = root; while(CurrentNode) { cout<<CurrentNode->data<<endl; if (CurrentNode->LeftChild) q.add(CurrentNode->LeftChild); if (CurrentNode->RightChild) q.add(CurrentNode->RightChild); CurrentNode = *q.Delete(CurrentNode); } } Program 5.7 : Level-order traversal of a binary tree
5.3 Binary Tree Traversal and Tree Iterators(Cont’) • Output : +*E*D/CAB • used the circular queue
5.3 Binary Tree Traversal and Tree Iterators(Cont’) void tree :: NoStackInorder() //inorder traversal of binary tree using a fixed amount of additional storage { if(!root) return; // empty binary tree TreeNode *top = 0, *LastRight=0, *p, *q, *r, *r1; p=q=root; while(1) { while(1) { if((!pLeftChild)&&(!pRightChild)) { //leaf node cout < < p data; break; } if (!pLeftChild) { //visit p and move to p RightChild cout < < p data; r=pRightChild; pRightChild=q; q=p; p=r; } else{ //move to p LeftChild r=pLeftChild; pLeftChild = q; q=p; p=r; } } //end of inner while
5.3 Binary Tree Traversal and Tree Iterators(Cont’) //p is a leaf node, move upward to a node whose //right subtree has not yet been examined TreeNode *av = p; while(1) { if(p = = root) return; if(!qLeftChild) { // q is linked via RightChild r = q RightChild; qRightChild = p; p = q; q=r; } else if (!qRightChild){ // q is linked via LeftChild r=qLeftChild; qLeftChild = p; p=q; q=r; cout << p data; } else //check if p is a RightChild of q if(q = = LastRight ){ r = top; LastRight = r LeftChild; top = r RightChild; // unstack r LeftChild = r RightChild = p; p = q; q = r; }
5.3 Binary Tree Traversal and Tree Iterators(Cont’) else { // p is LeftChild of q cout <<qdata; // visit q av LeftChild = LastRight; av RightChild = top; top = av; LastRight = q; r = q LeftChild; q LeftChild = p; // restore link to p r1 = q RightChild; q RightChild = r; p = r1; break; } } // end of inner while loop } // end of outer while loop } Program 5.8 : O(1) space inorder traversal
5.4 Additional Binary Tree Operations //Copy consturctor Tree :: Tree(const Tree&s) //driver { root = copy(s.root); } TreeNode*Tree :: copy(TreeNode *orignode) // Workhorse //This function returns a pointer to an exact copy of the binary tree rooted at orignode. { if(orignode) { TreeNode *temp = new TreeNode; temp data = orignode data; temp LeftChild = copy (orignode LeftChild); temp RightChild = copy (orignode RightChild); return temp; } else return 0; } Program 5.9 : Copying a binary tree
5.4 Additional Binary Tree Operations(Cont’) //Driver – assumed to be a friend of class Tree. int operator = = (const Tree & s, const Tree & t) { return equal (s.root, t.root); } //Workhorse – assumed to be a friend of TreeNode. int equal (TreeNode *a, TreeNode *b) //This function returns 0 if the subtrees at a and b are not equivalent. //Otherwise, it will return 1. { if ((!a)&&(!b)) return 1; //both a and b are 0 if (a&&b // both a and b are non-0 && (adata = = b data) //data is the same && equal (a LeftChild, b LeftChild) //left subtrees are the same && equal (a RightChild, b RightChild)) // right subtrees are the same return 1; return 0; } Program 5.10 : Binary tree equivalence
5.4 Additional Binary Tree Operations(Cont’) Figure 5.18 : Propositional formula in a binary tree
5.4 Additional Binary Tree Operations(Cont’) for all 2n possible truth value combinations for the n variables { generate the next combinationl replace the variables by their values; evaluate the formula by traversing the tree it points to in postorder; if(formula.rootvalue()) { cout << combination ; return; } } cout << “no satisfiable combination”; Program 5.11 : First version of satisfiability algorithm
5.4 Additional Binary Tree Operations(Cont’) void SatTree :: PostOrderEval() // Driver { PostOrderEval(root); } void SatTree :: PostOrderEval(SatNode *s) // Workhorse { if(s) { PostOrderEval(sLeftChild); PostOrderEval(sRightChild); switch(sdata) { case LogicalNot: svalue = !s RightChildvalue; break; case LogicalAnd: svalue = sLeftChildvalue&& sRightChildvalue; break; case LogicalOr: svalue = sLeftChildvalue|| sRightChildvalue; break; case LogicalTrue: svalue = TRUE; break; case LogicalFalse: svalue = FALSE; } } } Program 5.12 : Evaluating a formula
5.4 Additional Binary Tree Operations(Cont’) Figure 5.19 : A SwapTree example
5.5 Threaded Binary Trees Figure 5.20 : Threaded tree corresponding to Figure 5.10(b)
5.5 Threaded Binary Trees(Cont’) Figure 5.21 : An empty threaded binary tree