//************************************************************// //********* Intro. to Trees - January 27th, 2017*************// //**********************************************************// -Well, we've gone through "Don't Stop Me Now" and are on to the MJ tracks...this show needs to get on the road ------------------------------------------------ -So, Linked Lists, Stacks, Queues...they're nice, sure, but TREES are where data structures get real -All of these other data structures have been linear; trees can go in multiple directions -*technically you can imagine the other structures as 1D trees, but that's just getting cheeky -Their fundamental idea: how to move through information -REMEMBER: Trees are a SET of data structures, with many types of sub-trees (binary trees, BST's (WHICH ARE NOT JUST BINARY TREES), AVL trees, etc.) -So, in CS, a TREE is "an abstract model of a hierarchal structure"; they're an ADT that consists of nodes with a parent-child relationship -By this definition, a Linked List is *technically* a tree -Trees are "limited graphs"; aka, they have NO cycles; they have a fundamentally recursive structure (i.e. branching) -Some applications: -File Systems -Organization charts -Anything your puny mind can imagine! | /\ / \ / \ /\ /\ (...it's too hard to draw an ASCII tree :/ ) -In this class, FOR OUR PURPOSES, we will assume there are no duplicate nodes in a tree when dealing with non-numerical data (when dealing with integers, though...wellllll...) -IMPORTANT TERMS: -ROOT NODE: -The node where you enter the tree; it does NOT have a parent, and is almost always on the top of the tree -INTERNAL NODES: -A node with at least one child node -LEAF NODES (aka "External" nodes): -Nodes with no children; usually at the bottom of a branch -PARENT (of a node): -Node immediately above another node -ANCESTOR NODES: -All of the parents, grand-parent, great-grandparents, etc.,, of a node -CHILDREN (of a node): -The node(s) IMMEDIATELY below a node (just 1 level down) -DESCENDANTS (of a node): -The children, grandchildren, great-grandchiltren, etc. of a node -"Height" (of a node): -The # of nodes that need to be traversed to reach a leaf node/the end of a branch; in this class, we count from "bottom-up," so the height of a leaf node is 0 -If an internal node has a child that's a leaf, but a non-leaf child, then we count the height as if it's counting up from the non-leaf child (aka, always takes the higher #) -"Depth" (of a node): -The reverse of height, this is how many nodes you need to go up to reach the root node. IN THIS CLASS, THE "DEPTH" OF THE ROOT NODE IS 1 (yes, 1, NOT 0!!!); we count from "top-down" -Depth is the "level" of the tree; height talks about "what's below me?" for a node -SUBTREE: -A tree within the tree consisting of a node and its descendants -Can be any possible subtree within the tree (including the original tree, which is technically a "subtree" of itself) -So, what methods will you find in pretty much EVERY tree? -Generic methods: -int size(): returns the size of the tree -boolean isEmpty() -Iterator iterator(): -Iterable positions()" -Accessor methods (getting a node): -position root(): -positions parent(p): -Iterable children(p): -int numChildren(p): -Query methods (get infrmation about the node): -boolean isExternal(p): -boolean isInternal(p): -boolean isRoot(p): -NOTE: Trees are recursive data structures due to the way they "branch"; because of this, basically EVERY operation done on the tree (searching, adding, removing, etc.) is handled as a recursive method; while it is SOMETIMES possible to do this iteratively, usually these implementations are messier, more error-prone, and often more inefficient than just writing it recursively -BINARY TREES are an ADT type of tree where each node has AT MOST 2 children (a left/right child) -Can think of the children as an "ordered pair" -A binary tree contains a single root node with an ordered pair of children (which are themselves the root nodes of binary sub-trees) -Applications: -Some notation: n = # of nodes; e = # of external nodes; i = # of internal nodes; h = height -BT Properties: -e = i + 1 -h <= i -n = 2e - 1 -e <= 2^h -h <= (n-1) / 2 -BT's inherit all of the methods of a normal Tree ADT, but also has three methods for each node: -position left(p) -position right(p) -position sibling(p) -A BINARY SEARCH TREE is a special case of a Binary Tree, where the LEFT CHILD is ALWAYS smaller than the parent node, and the RIGHT CHILD is ALWAYS LARGER than the parent node -What happens to equal items? Well, that depends on the implementation -So, the left subtree contains ONLY items smaller than the root node, and the right subtree contains ONLY items larger than the root node -You might ask, "well, what if we end up with a tree where everything is on one side? Wouldn't that be inefficient, since its basically just a linked list then? Could we fix that problem?" Just you wait... -A BST is "BALANCED" when all of its leaf nodes (or at least as many as possible) are on the same level -In general, BST's can be REALLY out of whack and unbalanced without too many problems -TREE TRAVERSALS- -A TRAVERSAL visits all of a tree's nodes in a systematic order -For ALL trees, you can perform a "pre-order traversal" (visit node, then visit all of the left children, then visit all of the right children), a "post-order traversal" (), and a "level traversal" -"Pre" because you visit ALL of the left-most nodes first, "post" because you visit ALL of the right-most nodes first... -Level traversals just go down row-by-row (breadth-first search?) -We'll talk about this in more detail on Monday!