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)