1 / 109

Chapter 10 Trees

Chapter 10 Trees. Chien Chin Chen Department of Information Management National Taiwan University. Categories of Data-Management Operations (1/2). ADT operations fit into at least one of these categories: Insert data into a data collection. Delete data from a data collection.

lsmallwood
Télécharger la présentation

Chapter 10 Trees

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 10 Trees Chien Chin Chen Department of Information Management National Taiwan University

  2. Categories of Data-Management Operations (1/2) • ADT operations fit into at least one of these categories: • Insert data into a data collection. • Delete data from a data collection. • Ask questions about the data in a data collection. • Position-oriented ADTs: Operations that • Insert data into the ith position • Delete data from the ith position • Ask a question about the data in the ith position • Examples: list, stack, queue. • Value-oriented ADTs: Operations that • Insert data according to its value. • Delete data knowing only its value. • Ask a question about data knowing only its value. • Examples: sorted list.

  3. Categories of Data-Management Operations (2/2) • In this chapter, we talk about “Tree”, a very useful ADT in many real-world applications. • Position-oriented ADT: binary tree. • Value-oriented ADT: binary search tree.

  4. Terminology (1/3) • Trees are composed of nodes (vertex) and edges. • Trees are hierarchical. • Parent-child relationship between two nodes. • E.g., B and C are children of A. • Each node in a tree has at most one parent. • Except root, has no parent. • E.g., A. • A node that has no children is called a leaf of the tree. • E.g., C, D, E, F.

  5. Terminology (2/3) • Siblingrelationship: children of the same parent. • E.g., B and C. • Ancestor-descendant relationships among nodes. • A is an ancestor of D. • D is a descendant of A. • The root of any tree is an ancestor of every node in that tree. • Subtree of a tree: Any node and its descendants. A subtree example.

  6. Terminology (3/3) • A general treeT is a set of one or more nodes such that T is partitioned into disjoint subsets: • A single node r, the root. • Sets that are general trees, called subtrees of r. • The hierarchical property of tree: • Can be used to represent information that itself is hierarchical in nature. • E.g., family tree.

  7. A Binary Tree (1/2) • A binary tree is a set T of nodes such that either: • T is empty, or • T is partitioned into threedisjoint subsets: • A single node r, the root. • Two possibly empty sets that are binary trees, called the left subtree of r and the right subtree of r.

  8. A Binary Tree (2/2) • You can use binary trees to represent algebraic expressions. • Leafs are operands. • Evaluation manner: bottom-up. • The hierarchy specifies an unambiguous order for evaluating an expression. • Parentheses do not appear in these tree.

  9. A Binary Search Tree • A binary search tree is a binary tree. • But has the following properties for each node n: • n’s value is > all values in n’s left subtree TL. • n’s value is < all values in n’s right subtree TR. • Both TL and TR are binary search trees.

  10. The Height of Trees (1/3) • Height of a tree: • Number of nodes along the longest path from the root to a leaf. Height 3 Height 5 Height 7 Trees with the same nodes but different heights.

  11. The Height of Trees (2/3) • Level of a noden in a tree T: • If n is the root of T, it is at level 1. • If n is not the root of T, its level is 1 greater than the level of its parent. Level 1 Level 2 Level 3

  12. The Height of Trees (3/3) • Height of a tree T defined in terms of the levels of its nodes. • If T is empty, its height is 0. • If T is not empty, its height is equal to the maximum level of its nodes. • A recursive definition of height • If T is empty, its height is 0 • If T is not empty, height(T) = 1 + max{height(TL), height(TR)} r / \ TL TR

  13. Full Binary Trees • A binary tree of height h is fullif • Nodes at levels < h have two children each. • Recursive definition: • If T is empty, T is a full binary tree of height 0. • If T is not empty and has height h > 0, T is a full binary tree if root’s subtrees are both full binary trees of height h – 1.

  14. Complete Binary Trees (1/2) • A binary tree of height h is complete if • It is full to level h– 1. • Level h is filledfrom left to right.

  15. Complete Binary Trees (2/2) Another definition: • A binary tree of height h is complete if • All nodes at levels <= h– 2 have two children each, and. • When a node at level h– 1 has children, all nodes to its left at the same level have two children each. • When a node at level h– 1 has one child, it is a left child. Level 1 Level 2 Level 3 Level 4 Level 5

  16. Balanced Binary Trees • A binary tree is balanced if the heights of any node’s two subtrees differ by no more than 1 • Complete binary trees are balanced. • Full binary trees are complete and balanced. balanced unbalanced

  17. The ADT Binary Tree (1/9) • ADT design: • Properties of data: • TreeItemType: the type of items stored in the binary tree. E.g., int. • Root, left/right subtrees. • Operations: • createBinaryTree(in RootItem: TreeItemType) throw TreeException Creates a one-node binary tree whose root contains rootItem. Throw TreeException if allocation fails. root item left subtree right subtree

  18. The ADT Binary Tree (2/9) • createBinaryTree(in rootItem:TreeItemType, inout leftTree:BinaryTree, inout rightTree:BinaryTree) throw TreeException Create a binary tree whose root contains rootItem and has leftTree and rightTree, respectively, as its left and right subtrees. Makes leftTree and rightTree empty so they cannot be used to gain access to the new tree. Throw TreeException if allocation fails. • isEmpty():boolean {query} Determines whether this binary tree is empty.

  19. The ADT Binary Tree (3/9) • getRootData():TreeItemType throw TreeException Returns the data item in the root of a nonempty binary tree. Throws TreeException if the tree is empty. • setRootData(in newItem:TreeItemType) throw TreeException Replace the data item in the root of this binary tree with newItem, if the tree is not empty. However, if the tree is empty, create a root node whose data item is newItem and inserts the new node into the tree. If a new node cannot be created, TreeExcpetion is thrown.

  20. The ADT Binary Tree (4/9) • attachLeft(in newItem:TreeItemType) throw TreeException Attaches a left child containing newItem to the root of this binary tree. Throws TreeException if a new child node cannot be allocated. Also throws TreeException if the binary tree is empty or a left subtree already exists. • attachRight(in newItem:TreeItemType) throw TreeException

  21. The ADT Binary Tree (5/9) • attachLeftSubtree(inout leftTree:BinaryTree) throw TreeException Attaches leftTree as the left subtree of the root of this binary tree and makes leftTree empty so that it cannot be used to access this tree. Throws TreeException if the binary tree is empty or a left subtree already exists. • attachRightSubtree(inout rightTree:BinaryTree) throw TreeException

  22. The ADT Binary Tree (6/9) • detachLeftSubtree(out leftTree:BinaryTree) throw TreeException Detaches the left subtree of this binary tree’s root and retains it in leftTree. Throw TreeException if the binary tree is empty. • detachRightSubtree(out rightTree:BinaryTree) throw TreeException

  23. The ADT Binary Tree (7/9) • getLeftSubtree():BinaryTree Returns a copy of the left subtree of this binary tree’s root without detaching the subtree. Returns an empty tree if the binary tree is empty. • getRightSubtree():Binarytree

  24. The ADT Binary Tree (8/9) • preorderTraverse(in visit:FunctionType) Traverses this binary tree in preorder and calls the function visit() once for each node. • inorderTraverse(in visit:FunctionType) Traverses this binary tree in inorder and calls the function visit() once for each node. • postorderTraverse(in visit:FunctionType) Traverses this binary tree in postorder and calls the function visit() once for each node.

  25. The ADT Binary Tree (9/9) • Building an ADT binary tree. tree1.setRootData(‘F’) tree1.attachLeft(‘G’) tree2.setRootData(‘D’) tree2.attachLeftSubtree(tree1) tree3.setRootData(‘B’) tree3.attachLeftSubtree(tree2) tree3.attachRight(‘E’) tree4.setRootData(‘C’) binTree.createBinaryTree(‘A’,tree3,tree4) A B C D E F G Initially, all trees exist but are empty.

  26. Traversals of a Binary Tree (1/6) • A traversal visits each node in a tree. • You do something with or to the node during a visit. • For example, display or modify the data in the node. • With the recursive definition of a binary tree, you can construct a recursive traversal algorithm. • If the tree is not empty, the traversal algorithm must perform three tasks: • Display the data in the root. • Traverse the two subtrees (recursive … smaller problems). • The base case: If the tree is empty, the algorithm takes no action.

  27. Traversals of a Binary Tree (2/6) • The algorithm has three choice of when to visit the root. • Preorder traversal • Visit root before visiting its subtrees. • i.e., Before the recursive calls. • Inorder traversal • Visit root between visiting its subtrees. • i.e., Between the recursive calls. • Postorder traversal • Visit root after visiting its subtrees. • i.e., After the recursive calls.

  28. Traversals of a Binary Tree (3/6) • The pseudo code of the preorder traversal algorithm: preorder(in binTree:Binarytree) if(bintree is not empty) { Display the data in the root of binTree preorder(Left subtree of binTree’s root) preorder(Right subtree of binTree’s root) } // end if 60 60 20 10 40 30 50 70 Preorder: 20 70 10 40 30 50

  29. Traversals of a Binary Tree (4/6) • The pseudo code of the postorder traversal algorithm: postorder(in binTree:Binarytree) if(bintree is not empty) { postorder(Left subtree of binTree’s root) postorder(Right subtree of binTree’s root) Display the data in the root of binTree } // end if 60 Postorder: 10 30 50 40 20 70 60 20 70 10 40 30 50

  30. Traversals of a Binary Tree (5/6) • The task of tree traversal can be more than to display each item when you visit it. • Copy the item or even alter it. • Thus, you might devise many different traversal operations: • preorderTraverseAndDisplay, preorderTraverseAndCopy, … • A better solution: devise a traversal operation can call a function to perform a task on each item in the tree. • Function of displaying, copying, or altering items. • The client defines and passes this function as an argument to the traversal operation.

  31. Traversals of a Binary Tree (6/6) • preorderTraverse(in visit:FunctionType) • If you (client of the ADT binary tree) define a function display to display the data item in a node, you could invoke the traversal operation for the binary tree binTree by writing: binTree.preorderTraverse(display) The traversal operation would call display each time it visited a node in the tree.

  32. Possible Representations of a Binary Tree • ADT binary tree implementation: • An array-based representation. • Uses an array of tree nodes. • A pointer-based representation. • Nodes have two pointers that link the nodes in the tree. • In this implementation: • typedef string TreeItemType; • Each node in this tree contains a name (string data type), and has at most two descendant nodes.

  33. Array-based ADT Binary Tree (1/4) • Represent a binary tree by using an array of tree nodes. • Use a C++ class to define a node in the tree. • Each node contains a data portion, • And two indexes, on for each of the node’s children. typedef string TreeItemType; class TreeNode { private: TreeNode(); TreeNode(const TreeItemType &nodeItem, int left, int right); TreeItemType item;// data portion int leftChild;// index of left child int rightChild;// index of right child friend class BinaryTree; }

  34. Array-based ADT Binary Tree (2/4) const int MAX_NODES = 100; class BinaryTree { ... private: TreeNode tree[MAX_NODES]; int root; int free; } no child or empty tree tree[root].leftChild is the index of the root of the left subtree.

  35. As the tree changes due to insertions and deletions, its nodes may not be in contiguous elements of the array. Free List: A list of available (free) nodes in the array. Insertions/deletions: Obtain/return an available nodes from the list. Array-based ADT Binary Tree (3/4)

  36. Array-based ADT Binary Tree (4/4) • Example: • To delete node “Alan”. • To insert a new node?? • Practice yourself. 3 6 ?

  37. Array-based Representation of a Complete Binary Tree • If a binary tree is completeand remains complete. • A memory-efficient array-based implementation is possible AND attractive. 0 1 2 3 4 5 Children of tree[i]: tree[2*i+1](left) and tree[2*i+2](right) Parent of tree[i] is tree[(i-1)/2].

  38. Pointer-based ADT Binary Tree (1/15) • Use C++ pointers to link the nodes in the tree. typedef string TreeItemType; class TreeNode// node in the tree { private: TreeNode() {} TreeNode(const TreeItemType nodeItem, TreeNode *left = NULL, TreeNode *right = NULL) :item(nodeItem), leftChildPtr(left), rightChildPtr(right) {} TreeItemType item;// data portion TreeNode *leftChildPtr;// pointer to left child TreeNode *rightChildPtr;// pointer to right child friend class BinaryTree; }

  39. Pointer-based ADT Binary Tree (2/15) • In class BinaryTree: • The pointer root points to the tree’s root. • If the tree is empty, root is NULL. • root->leftChildPtr points to the root of the left subtree. • root->rightChildPtr points to the root of the right subtree.

  40. Pointer-based ADT Binary Tree (3/15) • TreeException, in page 519. /** @file BinaryTree.h */ #include "TreeException.h" #include "TreeNode.h" typedef void (*FunctionType)(TreeItemType& anItem); /* ADT binary tree. */ class BinaryTree { public: // constructors and destructor: BinaryTree(); BinaryTree(const TreeItemType& rootItem) throw(TreeException); BinaryTree(const TreeItemType& rootItem, BinaryTree& leftTree, BinaryTree& rightTree) throw(TreeException); BinaryTree(const BinaryTree& tree) throw(TreeException); virtual ~BinaryTree(); You can learn about virtual and protected in Chapter 8. Now, ignore virtual and read protected as private.

  41. Pointer-based ADT Binary Tree (4/15) // binary tree operations: virtual bool isEmpty() const; virtual TreeItemType getRootData() const throw(TreeException); virtual void setRootData(const TreeItemType& newItem) throw(TreeException); virtual void attachLeft(const TreeItemType& newItem) throw(TreeException); virtual void attachLeftSubtree(BinaryTree& leftTree) throw(TreeException); virtual void detachLeftSubtree(BinaryTree& leftTree) throw(TreeException); virtual BinaryTree getLeftSubtree() const throw(TreeException);

  42. Pointer-based ADT Binary Tree (5/15) virtual void preorderTraverse(FunctionType visit); virtual void inorderTraverse(FunctionType visit); virtual void postorderTraverse(FunctionType visit); protected: ... void preorder(TreeNode *treePtr, FunctionType visit); void inorder(TreeNode *treePtr, FunctionType visit); void postorder(TreeNode *treePtr, FunctionType visit); /** Deallocates memory for a tree. */ void destroyTree(TreeNode *& treePtr); private: /** Pointer to root of tree. */ TreeNode *root; }; // end BinaryTree

  43. Pointer-based ADT Binary Tree (6/15) /** @file BinaryTree.cpp */ #include <cstddef> // definition of NULL #include <new> // for bad_alloc #include "BinaryTree.h" // header file using namespace std; BinaryTree::BinaryTree() : root(NULL) {} // end default constructor BinaryTree::BinaryTree(const TreeItemType& rootItem) throw(TreeException) { try { root = new TreeNode(rootItem, NULL, NULL); } catch (bad_alloc e) { delete root; throw TreeException( "TreeException: constructor cannot allocate memory"); } // end try } // end constructor root root

  44. Pointer-based ADT Binary Tree (7/15) BinaryTree::BinaryTree(const TreeItemType& rootItem, BinaryTree& leftTree, BinaryTree& rightTree) throw(TreeException) { try { root = new TreeNode(rootItem, NULL, NULL); attachLeftSubtree(leftTree); attachRightSubtree(rightTree); } catch (bad_alloc e) { delete root; throw TreeException( "TreeException: constructor cannot allocate memory"); } // end try } // end constructor

  45. Pointer-based ADT Binary Tree (8/15) void BinaryTree::attachLeftSubtree(BinaryTree& leftTree) throw(TreeException) { if (isEmpty()) throw TreeException("TreeException: Empty tree"); else if (root->leftChildPtr != NULL) throw TreeException( "TreeException: Cannot overwrite left subtree"); else // Assertion: nonempty tree; no left child { root->leftChildPtr = leftTree.root; leftTree.root = NULL; } // end if } // end attachLeftSubtree root root leftTree … …

  46. Pointer-based ADT Binary Tree (9/15) bool BinaryTree::isEmpty() const { return (root == NULL); } // end isEmpty void BinaryTree::attachLeft(const TreeItemType& newItem) throw(TreeException) { if (isEmpty()) throw TreeException("TreeException: Empty tree"); else if (root->leftChildPtr != NULL) throw TreeException("TreeException: Cannot overwrite left subtree"); else // Assertion: nonempty tree; no left child { try { root->leftChildPtr = new TreeNode(newItem, NULL, NULL); } catch (bad_alloc e) { throw TreeException( "TreeException: attachLeft cannot allocate memory"); } // `end try } // end if } // end attachLeft root

  47. Pointer-based ADT Binary Tree (10/15) void BinaryTree::detachLeftSubtree(BinaryTree& leftTree) throw(TreeException) { if (isEmpty()) throw TreeException("TreeException: Empty tree"); else { leftTree = BinaryTree(root->leftChildPtr); root->leftChildPtr = NULL; } // end if } // end detachLeftSubtree root root leftTree … … BinaryTree::BinaryTree(TreeNode *nodePtr) : root(nodePtr) { }

  48. Pointer-based ADT Binary Tree (11/15) BinaryTree BinaryTree::getLeftSubtree() const throw(TreeException) { TreeNode *subTreePtr; if (isEmpty()) return BinaryTree(); else { copyTree(root->leftChildPtr, subTreePtr); return BinaryTree(subTreePtr); } // end if } // end getLeftSubtree Returns an empty tree if the binary tree is empty. root subTreePtr root copy … … … …

  49. Pointer-based ADT Binary Tree (12/15) void BinaryTree::copyTree(TreeNode *treePtr, TreeNode *& newTreePtr) const throw(TreeException) { // preorder traversal if (treePtr != NULL) { // copy node try { newTreePtr = new TreeNode(treePtr->item, NULL, NULL); copyTree(treePtr->leftChildPtr, newTreePtr->leftChildPtr); copyTree(treePtr->rightChildPtr, newTreePtr->rightChildPtr); } catch (bad_alloc e) { throw TreeException( "TreeException: copyTree cannot allocate memory"); } // `end try } else newTreePtr = NULL; // copy empty tree } // end copyTree Point to destination root node Point to source root node

  50. Pointer-based ADT Binary Tree (13/15) void BinaryTree::copyTree(TreeNode *treePtr, TreeNode *& newTreePtr) ... if (treePtr != NULL) newTreePtr = new TreeNode(treePtr->item, NULL, NULL); copyTree(treePtr->leftChildPtr, newTreePtr->leftChildPtr); copyTree(treePtr->rightChildPtr, newTreePtr->rightChildPtr); ... copyTree(root,tPtr) tPtr newTreePtr root treePtr newTreePtr copyTree(root->leftChildPtr, newTreePtr->leftChildPtr) treePtr … … … Preorder traversal!! NO Can newTreePtr be called by value ?

More Related