Download presentation
Presentation is loading. Please wait.
Published byFelicity Morrison Modified over 10 years ago
0
Lecture 18 Trees
1
Overview Definitions, Terminology, and Properties Binary Trees
Search Trees: Improving Search Speed Traversing Binary Search Trees
2
Searching in a Linked List (1/3)
To search for an element in a linked list involves pointer-chasing and checking consecutive nodes to find it (or not), i.e., it is sequential access, O(N) – can stop sooner for element not found if list is sorted To find the I’th element in an array or ArrayList is random access, O(1), but searching for a particular element even with an index is still sequential O(N) And with NodeLists, even though they support indexing dictated by Java’s list interface, to find the I’th element is also done (under the hood) by pointer-chasing and hence is O(N)
3
Searching in a Linked List (2/3)
Searching for E: start at A, beginning of list but A is not E, so look at next node B but B is not E, so look at next node C (and so on…) till… E is E, found it! or it isn’t in list – exit on null (unsorted) or first item greater (sorted)
4
Searching in a Linked List (3/3)
For N items, search time is O(N) unsorted: sequenctially check every node in list till element (“search key”) being searched for is found, or end of list is reached if in list, for a uniform distribution of keys, average search time is N/2 if not in list, it is N sorted: average search time is N/2 if found, N/2 if not found (the win!) we ignore issue of duplicates No efficient way to access Nth node in list Insert and remove similarly have average search time of N/2 to find the right place; dominates the O(1) amount of processing to re-link the list Is there another data structure that provides faster search time and still fast updating of the data structure?
5
Binary Search (1/5) Worst case for searching sorted linked list is checking every element i.e., sequential access We can do better with a sorted array which allows random access at any index Let’s demo binary search (“bisection”) for a sorted list of numbers Website:
6
Binary Search (2/5) For N items, search time is O(log2N) (since we reduce number of elements to search by half each time), very efficient! start in the middle keep bisecting the array by halving the index, deciding which half interval the search key lies in, until we land on that key or can’t subdivide further (not in array)
7
Binary Search (3/5) log2N is considerably smaller than N, especially for large N. So doing things in time proportional to log2N is better than doing them in proportion to N!
8
Binary Search (4/5) Because arrays are indexed, and can be searched quickly if sorted, using bisection Java ArrayLists are indexed too, so they share this advantage! But inserting and removing from ArrayLists is slow! Inserting into or deleting from middle of ArrayList causes all successor elements to be shifted over to make room. For arrays, you manage this yourself. Both have same performance hit Advantage of linked lists is insert/remove by manipulating pointer chain is faster [O(1)] than shifting elements [O(N)], but search can’t be done with bisection , a real downside if search is done frequently
9
Binary Search (5/5) Is there a data structure/Abstract Data Type that provides both search speed of sorted arrays and ArrayLists and insertion/deletion efficiency of linked lists? Yes, indeed! Trees!
10
Trees vs Linked Lists (1/2)
Singly linked list – collection of nodes where each node references only one neighbor, the node’s successor: Note we show the null element as a special “leaf” node – see next slide null
11
Trees vs Linked Lists (2/2)
Tree – also collection of nodes, but each node may reference multiple successors/children Trees can be used to model a hierarchical organization of data Leaf nodes are special nodes that contain no data or child pointers – they terminate root
12
Technical definition of a Tree
Finite set, T, of one or more nodes such that: T has one designated root node remaining nodes partitioned into disjoint sets: T1, T2, … Tn each Ti is also a tree, called subtree of T Look at the image on the right. Where have we seen such hierarchies like this before? root T1 T2 T3 Note: leaves omitted for simplicity
13
Inheritance Hierarchies as Trees
Animal Reptile Mammal Fish Dog Cat Moose Higher in inheritance hierarchy, more generic Animal is most generic Lower in inheritance hierarchy, more specific Dog is more specific than Mammal, which in turn is more specific than Animal
14
Containment Hierarchies as Trees
Levels of containment of GUI components Higher levels contain more components JFrame contains everything else Lower levels contained by all above them JPanels contained by MainPanel, which is contained by JFrame Note: This is not strictly a tree but a "directed graph" because there are several "cycles" of nodes pointing to each other
15
Tree Terminology A B C D E F G H I 1 2 3 4 5 6 7 8 9 10
A is the root node B is the parent of D and E D and E are children of B (C ---- F) is an edge 1, 2,…,9, 10 are external nodes or leaves (i.e., nodes with no children) A, B, C, D, E, F, G, H, I are internal nodes depth (level) of E is 2 (number of edges to root) height of the tree is 4 (max number of edges in path from root) degree of node B is 2 (number of children) D E F G H I
16
Binary Trees Each internal node has only 2 successors, called children
so, each internal node has degree 2 Recursive definition of binary tree: binary tree is either an: external node (leaf), or internal node (root) with two binary trees as children (left subtree and right subtree) Note: These nodes are similar to the linked list nodes, with one data and two child pointers A B C E D F G
17
Properties of Binary Trees (1/2)
(# leaf nodes) = (# internal nodes) + 1 (# nodes at level i) <= 2i (# leaf nodes) <= 2(height) (height) >= log2(# leaf nodes)
18
Properties of Binary Trees (2/2)
Binary tree is full when for every level i, there are 2i nodes (i.e., each level contains a complete set of nodes) thus, adding anything to the tree would increase its height Level 1 2 3 4
19
Binary Search Tree a.k.a BST (1/2)
Binary search tree stores keys in internal nodes such that, for every node, keys in left subtree are smaller, and keys in right subtree are larger Note: we depict nodes with the key inside the node, but in reality there will be a pointer to the data element that has the key as one of its properties, and two pointers to the child nodes M H P Node<Type> InternalNode<Type> _data _left _right Type key B J O Y A I L S
20
Binary Search Tree (2/2) Below is also binary search tree but much less balanced. Gee, it looks like a linked list! M Unbalanced H B A T V H Balanced B M A T V
21
Binary Search Tree Class (1/3)
What do binary search trees know how to do? much the same as sorted linked lists: insert, remove, isEmpty public class BinarySearchTree<Type extends Comparable<Type> > //generic again { private Node<Type> _root; public BinarySearchTree() { _root = new LeafNode<Type>(); // more about LeafNodes coming up! }
22
Binary Search Tree Class (2/3)
… public void insert(Type newData) { // . . . } public void remove(Type itemToRemove) { public Node<Type> search(Type itemToFind) { // ... public boolean isEmpty() {
23
Binary Search Tree Class (3/3)
Previously had “smart” sorted singly linked lists and specialized Stacks and Queues, that chained dumb nodes (having only a pointer to data and to next node, only set/gets). the list did all the work by maintaining prev and curr pointers to "where the action is" and did the operations to search for, insert or remove information Now we're going to have a dumb tree with smart internal nodes that will delegate using recursion thus tree will delegate to _root (first internal node) which will delegate to its appropriate child different from linear linked lists, stacks, queues: create specialized Node subclasses for internal and leaf nodes
24
Binary Search Tree: Generic Node (1/2)
Methods common to all “smart” binary tree nodes in abstract base class: public abstract class Node<Type extends Comparable<Type>> { public abstract Node<Type> search(Type itemToFind); public abstract Node<Type> insert(Type newData); public abstract Node<Type> remove(Type itemToRemove); public abstract Type swapKey(Type newKey); public abstract boolean isEmpty(); //accessors and mutators for instance variables elided. }
25
Binary Search Tree: Generic Node (2/2)
swapKey(…) used in remove when trying to remove a node with 2 children helper method for remove(), not in BinarySearchTree class as tree operation Make specific nodes which extend generic Node different pattern from previous data structures the subclasses will implement these abstract methods
26
Binary Search Tree: Internal Node (1/2)
Represents node with two children that hold data implementing Comparable<Type>, so three instance variables and their sets/gets left child contains either subtree, all of whose data is less than parent’s data, or a leaf node right child contains either subtree, all of whose data is greater than parent’s data, or a leaf node Node<Type> InternalNode<Type> _data _left _right Type _key data element Note: ignore data associated with each key, to focus on keys (to declutter)
27
Binary Search Tree: Internal Node (2/2)
// note two different uses of extends! First is like implements, second is “is-a” public class InternalNode<Type extends Comparable<Type>> extends Node<Type> { private Type _data; private Node<Type> _left; private Node<Type> _right; public InternalNode(Type data, Node<Type> leftNode,Node<Type> rightNode) { super(); _data = data; _left = leftNode; _right = rightNode; } // will redefine superclass methods soon . . .
28
Binary Search Tree: Leaf Node
A leaf node has no descendents or data it has methods for insertion, so it is a real class, not just null public class LeafNode<Type extends Comparable<Type>> extends Node<Type> { // will use default constructor // no instance variables // will redefine superclass methods soon, starting with recursive search… } LeafNode<Type>
29
Recursion – Turtles all the Way Down
“A well-known scientist (some say it was Bertrand Russell) once gave a public lecture on astronomy. He described how the earth orbits around the sun and how the sun, in turn, orbits around the center of a vast collection of stars called our galaxy. At the end of the lecture, a little old lady at the back of the room got up and said: "What you have told us is rubbish. The world is really a flat plate supported on the back of a giant tortoise." The scientist gave a superior smile before replying, "What is the tortoise standing on?" "You're very clever, young man, very clever," said the old lady. "But it's turtles all the way down!"” -Stephen Hawking, A Brief History of Time (1988)
30
Searching a Binary Tree Recursively (e.g., for I)
In InternalNode: if searchkey == nodekey found it! else if searchkey < nodekey search left else if searchkey > nodekey search right In LeafNode: return null; (if you get to leaf node, key is not in tree). Search path: start with root M and choose path to I (for reasonably balanced tree, M will be more or less “in the middle” similar to searching in sorted array (slide 3) O(log2N) time – Woo hoo! M H P O Y S B J A I L
31
Searching Simulation What if we want to know if 224 is in Tree?
123 252 224 16 What if we want to know if 224 is in Tree? Tree says “Hey Root! Ya got 224?” 123 says: “Let’s see. I’m not 224. But if 224 is in tree, it would be to my right. I’ll ask my right child and return its answer.” 252 says: “I’m not I better ask my left child and return its answer.” 224 says: “224? That’s me! Hey, caller (252) here’s your answer.” (returning node indicates that query is in tree) 252 says: “Hey, caller (123)! Here’s your answer.” 123 says: “Hey, Tree! Here’s your answer.”`
32
search(..): Tree and Leaf Nodes
BinarySearchTree is dumb so it delegates to root // search method for entire BinarySearchTree: public Node<Type> search(itemToFind) { return _root.search(itemToFind); } LeafNode returns null (indicates nothing found) // search method for a LeafNode: public Node<Type> search(Type itemToFind) { return null;
33
search(...): Internal Node
//InternalNode’s search method public Node<Type> search(Type itemToFind) { // if _data = itemToFind if (_data.compareTo(itemToFind) == 0) { return this; } //if itemToFind < _data, can only be in left tree else if(_data.compareTo(itemToFind) > 0) { return _left.search(itemToFind); else // itemToFind > _data, so check right tree { return _right.search(itemToFind); }} InternalNode checks its data if same, return this else, delegate and return answer!
34
Smart Node Approach Smart node approach makes our code clean, simple and elegant non-recursive method is much messier, involving explicit bookkeeping of the tree using a current and a next pointer we used the non-recursive method for sorted linked lists, but trees are more complicated, and recursion is easier
35
Insertion into a BST(1/2)
Example: Insert key Z O(Log2N) time, Yay! just a log2 search for proper leaf, and a few pointer manipulations at end Method: find leaf where key should appear in tree; it will place itself in the tree as follows: leaf makes new InternalNode with key as _data, itself (this) as _left leaf child, and new LeafNode as _right child in tree, replace this leaf with new internal node by having leaf return to its parent a reference to new internal node Y Z Leaf New place for node
36
Insertion into a BST(2/2)
Another example: Insert N M H Q O Y S B J A I L P Before: M H Q O Y S B J A I L P After: N
37
// in BinarySearchTree:
public void insert(Type newData) { //elided null case (make new internal node) _root = _root.insert(newData); // delegate } // in InternalNode: public Node<Type> insert(Type newData) { if (_data.compareTo(newData) > 0) { /* _left is set to whatever its child returns: either original child itself if it is an internal node or new node if it is a leaf node*/ _left = _left.insert(newData); else { _right = _right.insert(newData); // internal node always returns itself return this;} // in LeafNode: return new InternalNode<Type>(newData, this,new LeafNode<Type>());} Insertion Code Let’s see Tree insertion code for InternalNodes and for LeafNodes – insertion only done by leaf nodes! Old child node will return to parent what parent’s new child should be (internal node always returns itself, leaf node a new internal node) Note: We don’t deal with duplicates in this code
38
Insertion Simulation (1/4)
_root = _root.insert(newData); 123 says: “I’m an internal node. Hmm ... I am less than I’ll let my right child deal with it. // . . . if (_data.compareTo(newData) > 0) { _left = _left.insert(newData); } else { _right = _right.insert(newData); return this; // root is still pointing to 123 _root 123 252 16
39
Insertion Simulation (2/4)
_root = _root.insert(newData); 252 says: “I’m an internal node. I am greater than I’ll pass it on to my left child.” if (_data.compareTo(newData) > 0) { _left = _left.insert(newData); } // . . . return this; // 123’s right child is still 252 _root 123 252 16
40
Insertion Simulation (3/4)
123 252 16 Little left leaf says: “You belong here, 224. Let me make an internal node for you. I will be your left child and I’ll make a new leaf node to be your right child. I’ll return a link to you to my parent, 252, so you can take my place.” 224 return new InternalNode<Type>(newData, this, new LeafNode<Type>());
41
Insertion Simulation (4/4)
123 252 16 224 return new InternalNode<Type>(newData, this, new LeafNode<Type>()); 252 assigns returned link to new 224 node as its left child (not caring that child has changed) and returns a link to itself to 123, which doesn’t care either and (re-)assigns it to its right child Finally, 123 returns itself to root, and everyone is happy
42
Notes on Trees (1/2) Different arrival order of nodes results in different trees if you insert a node referencing data value of 18 into empty tree, that node will become root if you then insert a node referencing data value of 12, it will become left child of root however, if you insert node referencing 12 into an empty tree, it will become root then, if you insert one referencing 18, that node will become right child of root even with same nodes, different arrival order makes different trees! on average, for reasonably random (unsorted) arrival order and N >>1, trees will look similar in depth so order doesn’t really matter
43
Notes on Trees (2/2) When searching for a value, reaching another value that is greater than the one being searched for does not mean that the value being searched for is not present in tree (whereas it does in linked lists) it may well still be contained in left subtree of node of greater value that has just been encountered thus, where you might have given up in linked lists, you can’t give up here until you reach a leaf (but depth is roughly log2N which is much smaller than N/2!)
44
Remove: Simple two-leaf case
Node to remove has two leaf children just replace internal node and its leaf children with single leaf node does not matter which child chosen to replace with Remove P P has two leaf children P returns left child to O and is therefore replaced by it M H Q O Y S B J A I L P Before: After: M H Q O Y S B J A I L Poof!
45
Remove: one-leaf case Harder case: node to delete has one leaf child and one subtree child replace internal node with subtree child must pick correct child to replace with Remove O O has one leaf child, one subtree child choose the correct child with which to replace O, here the subtree P O replaces itself with P by returning P to its parent, Q M H Q O Y S B J A I L Before: P After: M H Q P Y S B J A I L Pow!
46
Remove: no-leaf case (1/3)
Hard case: node to remove has two subtree children brute force: just flag node for removal, and rewrite tree at a later time -- bad idea, because now every operation requires checking that flag. Instead, do the work right away this is tricky, because not immediately obvious which child should replace its parent non-obvious solution: first swap the data in node to be removed with data in a node that doesn’t have two children, then remove node using one of simpler removes
47
Remove: no-leaf case (2/3)
Use an auxiliary method, swapData swaps data in node to be removed with the data in the right-most node in its left subtree this node has a key value less than all nodes in the to-be removed node’s right subtree, and greater than all other nodes in its left subtree since it is a right-most node, it has at most one child this swap is temporary; next remove the node in the right-most position using simpler remove
48
Remove: no-leaf case (3/3)
H R O Y S B J A I L Before: Q N P U Remove R R has two internal children swap R with the right-most node in the left subtree, Q remove R (in its new position) using the one-child case After: M H R Q B J O Y A I L N R S P U Poof!
49
Remove: pseudocode for delete
For InternalNode: if nodekey == removekey // found it if one subtree is empty // do one-leaf remove return the other subtree else //two non-empty nodes so do complex remove swap with the right-most node in its left subtree tell that right-most node to remove InternalNode code continued on side For LeafNode: do nothing, just return reference to this leaf // recurse down else if nodekey > removekey tell left to try to remove else nodekey < removekey tell right to try to remove // internal nodes always return themselves // but potentially after a data swap so // contents may have changed! return this
50
Remove: leaf and root Code
Starts as usual with delegating to root: // in BinarySearchTree: public void remove(Type itemToRemove) { _root = _root.remove(itemToRemove); } Leaf node handles trivial case – does nothing: // in LeafNode: public Node<Type> remove(Type itemToRemove) { return this;
51
Remove: Internal Node Code (1/2)
// otherwise, let my children handle it public Node<Type> remove(Type itemToRemove) { Node<Type> nodeToReturn = this; if (_data.compareTo(itemToRemove) == 0){ // code to perform deletion on next slide } else if (_data.compareTo(itemToRemove) > 0){ _left = _left.remove(itemToRemove);} else if (_data.compareTo(itemToRemove) < 0){ _right = _right.remove(itemToRemove);} // always returns itself, possibly after // data swap return nodeToReturn; Internal node handles bulk of work in the ‘remove’ algorithm simplified by helper method: swapKey also simplified by delegating (via recursion) to children - LeafNode handles trivial case. // in InternalNode: public Node<Type> remove(Type itemToRemove) { Node<Type> nodeToReturn = this; if (_data.compareTo(itemToRemove) == 0){ // code to perform deletion on next slide }
52
Remove: Internal Node Code (2/2)
// otherwise, let my children handle it // in InternalNode’s remove method: // this is the node to delete, so // if one node is a leaf, replace // this node with other node, which // could be an internal node or a leaf if (_data.compareTo(itemToRemove) == 0){ if (_left.isEmpty()){ nodeToReturn = _right; } else if (_right.isEmpty()){ nodeToReturn = _left; // hard case: no leaf children so swap // with right-most node in left subtree else { // get the data from the node we swapped // and use it to update _data _data = _left.swapKey(_data); // remove the swapped node: // call remove again to do actual deletion // and ensure pointers get set properly _left = _left.remove(itemToRemove); }
53
Remove: swapKey code public Type swapKey(Type keyToDelete){
// If we have a right child, ask it // to swap – recurse till hit leaf // so there can be no children // “further to the right” if(!_right.isEmpty()) { return _right.swapKey(keyToDelete); } // Else, found rightmost node to swap else { Type rightMostData = _data; _data = keyToDelete; return rightMostData;}}
54
Implementing isEmpty BinarySearchTree acts as usual and delegates message to _root InternalNode will return false, LeafNode will return true true means asked a LeafNode, so there are no InternalNodes in the tree (it is empty) false means asked an InternalNode, so there is at least one InternalNode in the tree (it is not empty)
55
Traversing a Binary Tree (1/2)
We often want to access every node in tree so far, we have only searched for a single item we can use a traversal algorithm to perform some arbitrary operation on every node in tree Many ways to traverse nodes in tree order children are visited is important three traversal types: inorder, preorder, postorder Exploit recursion! subtree has same structure as tree
56
Traversing a Binary Tree (2/2)
We’ll add a print method to our node: public abstract class Node<Type extends Comparable<Type>> { //other methods elided public abstract void print(); } LeafNode’s implementation of print() will be an empty method InternalNode’s implementation will differ depending on traversal type
57
Inorder Traversal of BST
traverse left subtree output root traverse right subtree In this ordered tree, prints keys alphabetically. Inorder traversal of Binary Search Tree traverses elements in sorted order. public void inOrderPrint() { _left.inOrderPrint(); // method to write a letter; // not included in slides: this.writeCharacter(); _right.inOrderPrint(); } M H P B J O Y A I L S A B H I J L M O P S Y
58
Preorder Traversal of BST
output root traverse left subtree traverse right subtree public void preOrderPrint() { this.writeCharacter(); _left.preOrderPrint(); _right.preOrderPrint(); } M H P B J O Y A I L S M H B A J I L P O Y S
59
Postorder Traversal of BST
traverse left subtree traverse right subtree output root public void postOrderPrint() { _left.postOrderPrint(); // method to write a letter; // not included in slides: _right.postOrderPrint(); this.writeCharacter(); } To learn more about the exciting world of trees, take CS16 (CSCI0160): Introduction to Algorithms and Data Structures M H P B J O Y A I L S A B I L J H O S Y P M
60
Prefix, Infix, Postfix Notation for Arithmetic Expressions
Infix, Prefix, and Postfix refer to where the operator goes relative to its operands Infix: (fully parenthesized) ((1 * 2) + (3 * 4)) - ((5 - 6) + (7 / 8)) Prefix: - + * 1 2 * / 7 8 Postfix: 1 2 * 3 4 * / + - Graphical representation for equation:
61
Using Prefix, Infix, Postfix Notation
When you type an equation into a spreadsheet, you use Infix; when you type an equation into many Hewlett-Packard calculators, you use Postfix, also known as “Reverse Polish Notation,” or “RPN,” after its inventor Polish Logician Jan Lukasiewicz (1924) Easier to evaluate Postfix because it has no parenthesis and evaluates in a single left-to-right pass Use Dijkstra’s 2-stack shunting yard algorithm to convert from user- entered Infix to easy-to-handle Postfix – compile or interpret it on the fly
62
Dijkstra’s infix-to-postfix Algorithm (1/2)
Tushar and Anandan Dijkstra’s infix-to-postfix Algorithm (1/2) 2 stack algorithm for single-pass Infix to Postfix conversion, using operator precedence (a + (b * (c ^ d))) a b c d ^ * + Use rule matrix to implement strategy A) Operands are pushed onto operand stack; operators are pushed in precedence order onto the operator stack B) When precedence order would be disturbed, pop operator stack until order is restored, evaluating each pair of operands popped from the operand stack and pushing the result back onto the operand stack. Note that equal precedence displaces. At the end of the statement (marked by ; or CR) all operators are popped. C) “(“ starts a new substack; “)” pops until its matching “(“ A A A A C A B B B C A A B B C A A A B C A A A A E Incoming Operator ( ^ */ +- e ( ^ */ +- ) Top of Stack
63
Dijkstra’s infix-to-postfix Algorithm (2/2)
(a + (b * (c ^ d))) a b c d ^ * + Incoming Operator Top of Stack ( ^ */ +- ) Operand Stack ( ^ */ +- e A A A A C A B B B C A A B B C A A A B C A A A A E - -56 64 8 4 * 16 3 Precedence Checker Operator Stack 2
64
Challenge Questions How would you print the elements of a Binary Search Tree in increasing order? How would you find the ‘successor’ (i.e., next greatest number) of a node in a Binary Search Tree?
65
Challenge Questions Solutions
Q: How would you print the elements of a Binary Search Tree in increasing order? A: You would traverse the BST in-order Q: How would you find the ‘successor’ (i.e., next greatest number) of a node in a Binary Search Tree? A: The pseudo-code for the solution is as follows: if node.hasRight() node=node.right() while(node.hasLeft()) node=node.left() return node
66
Announcements DoodleJump late handin is tonight at 11:59PM
Tetris Design Checks are Friday through Monday. They will be held in the 4th floor atrium. Be sure to sign up, or you will get a 0 for the design check portion of your Tetris grade HW3 is released today. It is due Saturday Nov. 15, at 5PM Life After Brown lecture series: Adam Leventhal’01, Delphix CTO, Wednesday at noon in CIT 368
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.