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
17-03-09 Trees • Tree structures are a breakthrough in data organization, for they allow us to implement a host of algorithms much faster than when using linear data structures, such as arrays or linked lists. • Trees also provide a natural organization for data, and consequently have become ubiquitous structures in file systems, graphical user interfaces, databases, websites, and many other computer systems. Trees ACS-2947 Week 8 What is a Tree? • • • Formal Definition of a Tree In computer science, a tree is an abstract model of a hierarchical structure A tree consists of nodes with a parent-child Sales relation Applications: • Organization charts • File systems • Programming environments US Europe • Computers”R”Us Manufacturing InternaAonal Laptops Asia R&D Desktops Canada Node Relationships • • • A node v is internal if it has one or more children. If T is nonempty, it has a special node, called the root of T , that has no parent. • Each node v of T different from the root has a unique parent node w; every node with parent w is a child of w. • Note that a tree can be empty, meaning that it does not have any nodes. • This convention also allows us to define a tree recursively such that a tree T is either empty or consists of a node r, called the root of T, and a (possibly empty) set of subtrees whose roots are the children of r. • A • A node v is external if v has no children also known as leaves. • Node Relationships Two nodes that are children of the same parent are siblings • Formally, we define a tree T as a set of nodes storing elements such that the nodes have a parent-child relationship that satisfies the following properties: B E C F G D H • I J K A node u is an ancestor of a node v if u = v or u is an ancestor of the parent of v. Conversely, we say that a node v is a descendant of a node u if u is an ancestor of v. The subtree of T rooted at a node v is the tree consisting of all the descendants of v in T (including v itself). A B E C F I J G D H K 1 17-03-09 Tree terminology • Edges and Paths in Trees Root: node without a parent • Depth of a node: number of ancestors • Height of a tree: maximum depth of any node (3) • A 2 B E C D 3 F I J • G H K An edge of tree T is a pair of nodes (u,v) such that u is the parent of v, or vice versa. A path of T is a sequence of nodes such that any two consecutive nodes in the sequence form an edge. A B E C F I J G D H K Ordered Trees • A tree is ordered if there is a meaningful linear order among the children of each node; • That is, we purposefully identify the children of a node as being the first, second, third, and so on. • Such an order is usually visualized by arranging siblings left to right, according to their order. 2 17-03-09 The Tree Abstract Data Type • As we did with positional lists in Section 7.3, we define a tree ADT using the concept of a position as an abstraction for a node of a tree. • An element is stored at each position, and positions satisfy parent-child relationships that define the tree structure. • The Tree Abstract Data Type Position • Accessor Methods A position object for a tree supports the method: • getElement(): Returns the element stored at this position. The Tree Abstract Data Type • • Query Methods The Tree Interface public interface Tree<E> extends Iterable{ Position<E> root( ); Position<E> parent(Position<E> p) throws IllegalArgumentException; Iterable<Position<E>> children(Position<E> p) throws IllegalArgumentException; int numChildren(Position<E> p) throws IllegalArgumentException; • boolean isInternal(Position<E> p) throws IllegalArgumentException; General Methods boolean isExternal(Position<E> p) throws IllegalArgumentException; boolean isRoot(Position<E> p) throws IllegalArgumentException; int size( ); boolean isEmpty( ); Iterator<E> iterator(); Iterable<Position<E>> positions(); } 3 17-03-09 An AbstractTree Base Class • While an interface is a type definition that includes public declarations of various methods, an interface cannot include definitions for any of those methods. • In contrast, an abstract class may define concrete implementations for some of its methods, while leaving other abstract methods without definition. • An abstract class is designed to serve as a base class, through inheritance, for one or more concrete implementations of an interface. • When some of the functionality of an interface is implemented in an abstract class, less work remains to complete a concrete implementation. • We will define an AbstractTree base class, demonstrating how many tree-based algorithms can be described independently of the low-level representation of a tree data structure. • If a concrete implementation provides three fundamental methods—root(), parent(p), and children(p)— all other behaviors of the Tree interface can be derived within the AbstractTree base class. Tree Depth Let p be a position within tree T. • • We define the height of a tree to be equal to the maximum of the depths of its positions (or zero, if the tree is empty). • It is easy to see that the position with maximum depth must be a leaf. The depth of p is the number of ancestors of p, other than p itself. • Note that this definition implies that the depth of the root of T is 0. The depth of p can also be recursively defined as follows: • Tree Height • • If p is the root, then the depth of p is 0 • Otherwise, the depth of p is one plus the depth of the parent of p BINARY TREES • A binary tree is an ordered tree with the following properties: 1. Every node has at most two children. 2. Each child node is labeled as being either a left child or a right child. 3. A left child precedes a right child in the order of children of a node. 4 17-03-09 Binary Trees • The subtree rooted at a left or right child of an internal node v is called a left subtree or right subtree, respectively, of v. • A binary tree is proper if each node has either zero or two children. Some people also refer to such trees as being full binary trees. • Thus, in a proper binary tree, every internal node has exactly two children. • A binary tree that is not proper is improper. E.g. • • An arithmetic expression can be represented by a binary tree whose leaves are associated with variables or constants, and whose internal nodes are associated with one of the operators +, −, ∗, and /, as demonstrated in Figure 8.6. Each node in such a tree has a value associated with it. • If a node is leaf, then its value is that of its variable or constant. • If a node is internal, then its value is defined by applying its operation to the values of its children. A typical arithmetic expression tree is a proper binary tree, since each operator +, −, ∗, and / takes exactly two operands. A Recursive Binary Tree Definition • Incidentally, we can also define a binary tree in a recursive way. In that case, a binary tree is either: • An empty tree. • A nonempty tree having a root node r, which stores an element, and two binary trees that are respectively the left and right subtrees of r. We note that one or both of those subtrees can be empty by this definition. This tree represents the expression ((((3+1)∗3)/((9−5)+2))−((3∗(7−4))+6)) The value associated with the internal node labeled “/” is 2. A Binary Tree ADT • A binary tree is a specialization of a tree that supports three additional accessor methods: 5 17-03-09 Our Binary Tree Interface • Java interface corresponding to our Binary Tree ADT • This interface extends the Tree to add the three new behaviors. • Defining an Abstract Tree Base Class Binary tree is expected to support all the functionality that was defined for general trees (e.g., root, isExternal, parent), and the new behaviors left, right, and sibling. public interface BinaryTree<E> extends Tree<E>{ Position<E> left(Position<E> p) throws IllegalArgumentException; Position<E> right(Position<E> p) throws IllegalArgumentException; Position<E> sibling(Position<E> p) throws IllegalArgumentException; } Implementing Trees • The AbstractTree and AbstractBinaryTree classes that we have defined thus far in this chapter are both abstract base classes. • Although they provide a great deal of support, neither of them can be directly instantiated. • We have not yet defined key implementation details for how a tree will be represented internally, and how we can effectively navigate between parents and children. Linked Structure for Binary Trees • A natural way to realize a binary tree T is to use a linked structure • with a node that maintains references to the element stored at a position p and to the nodes associated with the children and parent of p. 6 17-03-09 LinkedBinaryTree Update Methods • The Tree and BinaryTree interfaces defines methods for inspecting an existing tree, yet they do not declare any update methods. • We now need to have ways for changing the structure of content of a tree. 7 17-03-09 Performance of the Linked Binary Tree 8 17-03-09 Array-Based Implementation of a Binary Tree • An alternative representation of a binary tree T is based on a way of numbering the positions of T . For every position p of T , let f (p) be the integer defined as follows. • If p is the root of T, then f(p)=0 • If p is the left child of position q, then f(p) = 2f(q) + 1 • If p is the right child of position q, then f(p) = 2f(q) + 2 Level Numbering • For example, in Figure (b), there are no nodes with level numbering 13 or 14, because the node with level numbering 6 has no children. • The numbering function f is known as a level numbering of the positions in a binary tree T, for it numbers the positions on each level of T in increasing order from left to right. • Note well that the level numbering is based on potential positions within a tree, not the actual shape of a specific tree, so they are not necessarily consecutive. Example of Array-Based Binary Tree a) b) Analyzing an Array-Based Binary Tree • One advantage is that a position p can be represented by the single integer f(p), and that position-based methods such as root, parent, left, and right can be implemented using simple arithmetic operations on the number f(p). • A drawback of an array representation is that many update operations for trees cannot be efficiently supported. • Array-Based Implementation of a Binary Tree For example, removing a node and promoting its child takes O(n) time because it is not just the child that moves locations within the array, but all descendants of that child. Linked Structure of General Trees • When representing a binary tree with a linked structure, each node maintains fields left and right as references to individual children. • For a general tree, there is no limit on the number of children that a node may have. • A natural way to realize a general tree T as a linked structure is to have each node store a single container of references to its children. 9 17-03-09 Linked Structure of General Trees Performance of a Linked General Tree • We let cp denote the number of children of a position p, and dp its depth. The space usage is O(n). The structure of a node A larger portion of the data structure associated with a node and its children Tree Traversal Algorithms • The traversal of a tree T is a systematic way of accessing, or “visiting,” all the positions of T . • The action associated with the “visit” of a position p depends on the application of this traversal, and could involve anything from incrementing a counter to performing some complex computation for p. Preorder Traversal • In a preorder traversal of a tree T , the root of T is visited first and then the sub-trees rooted at its children are traversed recursively. • If the tree is ordered, then the subtrees are traversed according to the order of the children. Postorder Traversal • The postorder traversal algorithm can be viewed as the opposite of the preorder traversal • it recursively traverses the subtrees rooted at the children of the root first, and then visits the root (hence, the name “postorder”) 10 17-03-09 Breadth-First Tree Traversal • Another approach is to traverse a tree so that we visit all the positions at depth d before we visit the positions at depth d + 1. Such an algorithm is known as a breadth-first traversal. Inorder traversal of a Binary Tree • During an inorder traversal, we visit a position between the recursive traversals of its left and right subtrees. • • The inorder traversal of a binary tree T can be informally viewed as visiting the nodes of T “from left to right.” Indeed, for every position p, the inorder traversal visits p after all the positions in the left subtree of p and before all the positions in the right subtree of p. Implementing Tree Traversals in Java • Recall: When first defining the tree ADT, we stated that tree T must include the following supporting methods: • iterator(): Returns an iterator for all elements in the tree. • positions(): Returns an iterable collection of all positions of the tree. 11 17-03-09 Implementing Tree Traversals in Java • We did not make any assumption about the order in which these iterations report their results. • In this section, we will demonstrate how any of the tree traversal algorithms we have introduced can be used to produce these iterations as concrete implementations within the AbstractTree or AbstractBinaryTree base classes. Implementing Tree Traversals In Java • First, we note that an iteration of all elements of a tree can easily be produced if we have an iteration of all positions of that tree. Preorder Traversals • To implement the positions() method, we have a choice of tree traversal algorithms. • Given that there are advantages to each of those traversal orders, we provide public implementations of each strategy that can be called directly by a user of our class. • • Our goal is to provide a public method preorder(), as part of the AbstractTree class, which returns an iterable container of the positions of the tree in preorder. • For ease of implementation, we choose to produce a snapshot iterator, returning a list of all positions. • The public preorder method below has the responsibility of creating an empty list for the snapshot buffer, and invoking the recursive method at the root of the tree (assuming the tree is nonempty). We rely on a java.util.ArrayList instance as an Iterable instance for the snapshot buffer. We can then trivially adapt one of those as a default order for the positions method of the AbstractTree class. Preorder Traversals • We begin by defining a private utility method, preorderSubtree, which allows us to parameterize the recursive process with a specific position of the tree that serves as the root of a subtree to traverse. • (We also pass a list as a parameter that serves as a buffer to which “visited” positions are added.) 12 17-03-09 Postorder Traversal • We implement a postorder traversal using a similar design as we used for a preorder traversal. • • Difference: “visited” position is not added to a postorder snapshot until after all of its subtrees have been traversed Both the recursive utility and the top-level public method are given Breadth-First Traversal • The breadth-first traversal algorithm is not recursive; it relies on a queue of positions to manage the traversal process • We will use the LinkedQueue class Inorder Traversal • • The inorder traversal algorithm, because it explicitly relies on the notion of a left and right child of a node, only applies to binary trees. • We therefore include its definition within the body of the AbstractBinaryTree class. • We use a similar design to our preorder and postorder traversals, with a private recursive utility for traversing subtrees. Because the iterator( ) method relies on positions(), it will also use inorder when reporting the elements of a binary tree. 13