Week9-BST-Worksheets
Week9-BST-Worksheets
Part 1: Warm-Up
Before we write any more code for BST deletion, we will look at an example to gain some intuition about how we could delete
values from a binary search tree.
1. Suppose you have to delete a value from the BST below. What would be an extremely easy value to delete, without
changing the rest of the tree?
A leaf
2. Suppose instead you have to delete root value, 70. Ugh. One strategy is to find another value in the tree that can replace
the 70 but leave the rest of the BST unchanged.
Could 110 replace the 70? No Could 20 replace the 70? No Could 98 replace the 70? No
Exactly which values can replace the 70, but leave the rest of the BST unchanged?
largest value of the left tree , smallest value of the right tree ???
class BinarySearchTree:
def delete(self, item: Any) -> None:
"""Remove *one* occurrence of <item> from this BST.
Preconditions:
- not self.is_empty()
"""
Now, we’ll lead you through the cases to develop an implementation of the BinarySearchTree.delete root method, in a
similar fashion to what we did for Tree.delete root last week.
Case 1: self is a leaf
Suppose self is a leaf (i.e., its left and right subtrees are empty). Think about should happen in this case. In the space below,
(1) fill in the if condition to check whether self is a leaf, and (2) fill in the body of the if branch to implement delete root
for this case. Review the BST reprsentation invariants!
Now suppose we want to delete the root of each tree. The simplest approach is to use the “promote a subtree” technique from
last week. Review this idea, and then fill in the conditions and implementations of each elif.
1. For this case, as we discovered earlier, we can extract a value from one of the subtrees and use it to replace the current
root value. We need to do so carefully, to preserve the binary search tree property, since this is a representation invariant!
Look at the sample BST above, and suppose we want to replace the root 13. Circle the value(s) in the subtrees that we
could use to replace the root, and make sure you understand why these values (and only these values) work.
2. Since there are two possible values, you have a choice about which one you want to pick. In the space below, write a
helper method that you could call on self. left or self. right to extract the desired value, and then use that helper
to complete the implementation of delete root.
3. Check your assumptions: did you assume that the value you were extracting is a leaf? Consider the following tree...
CSC148 - Investigating the Efficiency of Binary Search Trees
1. Recall our implementation of BinarySearchTree. contains :
class BinarySearchTree:
def __contains__(self, item: Any) -> bool:
if self.is_empty():
return False
elif item == self._root:
return True
elif item < self._root:
return item in self._left # self._left.__contains__(item)
else:
return item in self._right # self._right.__contains__(item)
Crucially, after comparing the item against the root of the BST, only one subtree is recursed into. To make sure you
understand this idea, suppose we have the following BST, and perform three searches, for the items 25, 10, and 4,
respectively. Circle all the values that are compared against the target item when we do each search.
Even though you should have circled a di↵erent number of tree values in each of the three diagrams, the number of
values is always less than or equal to the height of each tree.
Because BinarySearchTree. contains only ever recurses into one subtree, each recursive call goes down one level
in the tree. So at most one item per level is ever compared against the item being searched for.
So to better understand the running time of this algorithm, we need to investigate how the height of a BST can grow
as we insert more items into it.
2. Recall that the BST insertion algorithm from lecture always inserts a new item into an “empty spot” at the bottom of a
BST, so that the new item is a leaf of the tree.
(a) Suppose we start with an empty BST, and then insert (b) Suppose we start with an empty BST, and then insert
the items 1, 2, 3, 4, 5, 6 into the BST, in that or- the items 4, 2, 3, 5, 1, 6 into the BST, in that or-
der. Draw what the final BST looks like. der. Draw what the final BST looks like.
3. Write down the height of each BST you drew in the previous question. (You can do so beside or underneath the diagram.)
4. Let n be a non-negative integer, and suppose we want a BST that contains the values 1, 2, ..., n. What is the maximum
possible height of the BST?
5. Now suppose we want to find the minimum possible height of the BST. We’re going to investigate this in an indirect way:
for every height h, we’re going to investigate what the maximum number of values can be stored in a binary tree of height
n. Let’s try to find a pattern.
(a) Suppose we have a BST of height 0. What’s the maximum possible number of values in the BST? (Hint: there’s only
one kind of BST with height 0.)
(b) Suppose we have a BST of height 1. What’s the maximum possible number of values in the BST? (Draw an example.)
(c) Suppose we have a BST of height 2. What’s the maximum possible number of values in the BST? (Draw an example.)
(e) Suppose we have a BST of height 148. What’s the maximum possible number of values in the BST? (Don’t draw an
example, but find a pattern from your previous answers.)
(f) Suppose we have a BST of height h and that contains n values. Write down an inequality of the form n ... to relate
n and h. (This is a generalization of your work so far.)
(g) Finally, take your inequality from the previous part and isolate h. This produces the answer to our original question:
what is the minimum height of a BST with n values?