CS201 - Spring 2014 - Class 24
exercises
binary tree applications
binary search trees
- we saw that search is O(n) time to find something in a tree. Can we do better?
- binary search trees speed up the searching process by keeping the tree in a structured order. In particular:
- data in left tree < this.data() <= data in right tree
- what are the implications of this?
- all items to the left are less than the value at the current node
- all items to the right are greater than or equal to the value of the current node
- how does this help us when it comes to searching?
- at each node, we can compare the value we're looking for to the value at this node and we know which branch it's down!
public boolean search(E item){
if( data.equals(item) ){
return true;
}else if( isLeaf() ){
return false;
}else{
if( item.compareTo(data) < 0 ){
return left.search(item);
} else {
return right.search(item);
}
}
}
- notice that now rather than recursing on both the left and the right in our search method, we recurse on one or the other
- has a similar feel to binary search
- what is the running time?
- O(h)
- when is this a good running time and when is this a bad running time?
- Good: when the tree is complete (or near complete) then O(h) = O(log n)
- Bad: when the tree is a twig (or near a twig) then O(h) = O(n) so we haven't gained anything
some more methods on binary search trees
- How can we find the minimum value in the tree?
- left-most value in the tree
- running time? O(h)
- Max?
- right-most value in the tree
- running time? O(h)
- traversal: what kind of tree traversal would make sense?
- in-order
- visit nodes to the left first
- then visit this node
- finally, visit nodes to the right
- in-order traversal will print them in sorted order
- successor and predecessor
- sometimes we may want to know where the predecessor or successor is in the tree, that is, the previous or next in the sequence of data
- given a node in a tree, where is it's predecessor and successor?
- the simple case:
- predecessor is the right-most node of the left subtree, i.e. the largest node of all of the elements that are less than a node
- successor is the left-most node of the right sub-tree, i.e. the smallest node of all of the elements that are larger than a node
- complications: what if a node doesn't have a left or right subtree?
- it could be the max or the min, in which case, it might not have a success or predecessor
- successor: what if there is no right subtree?
- let x be a node with no right subtree
- let y = successor(x)
- we know that predecessor(y) = x
- to find the predecessor of y, we'd look at the right most node of the left subtree
- so, to find the successor of x
- keep going up as long as we're a right child
- when we're not a right child anymore, then that's the successor of x
- predecessor is similar
- what are the running times of predecessor and successor? O(h)
- inserting into a binary tree: assuming no duplicates, how can we insert into a binary tree?
- always add to a leaf node
- traverse down to some leaf node similar to search
- add a node to the left or right depending on whether it is larger than or smaller than the leaf
- running time? O(h)
- deleting from a binary tree
- let's say you're given a node (i.e. a BinaryTree) and you want to delete it
- 3 cases:
- 1) it is a leaf: just delete it and set that child of the parent's to an empty node
- 2) it only has one child: splice it out
- 3) it has two children: replace x with it's successor in the list!
- we know the successor is a leaf because we have a left subtree, so it's easy to remove
- we know the successor is larger than anything in our left subtree (it's the largest of the left subtree)
- we know the successor is smaller than anything in our right subtree (it's smaller than x)
- running time? O(h)