Michael Eckmann - Skidmore College - CS 206 - Fall 2008
Today’s Topics• Questions? Comments?• Example use of Binary Search Trees (see
Graphics notes: 2006-03-24)• Binary Search trees
–Continue: Delete a key–Consider other methods–Consider how to handle duplicate values
• General recursion ideas
Delete a key in a BST• First, start with currNode = root
• Go down the tree until currNode.key == searchkey. Each step
down the tree change currNode to be either the left or right child.
• So, when the above step is done, we have currNode.parent as the
parent and currNode as the node to delete.
Delete a key in a BST• There are several cases to consider
– 1) if searchkey was not found
– 2) currNode == root and currNode.left == null– 3) currNode == root and currNode.right == null
– 4) currNode != root and currNode.left == null– 5) currNode != root and currNode.right == null
– 6) currNode == root and both right and left are not null– 7) currNode != root and both right and left are not null
Delete a key in a BST• There are several cases to consider
– 1) if searchkey was not found
– done
– 2) currNode == root and currNode.left == null
– make root.right be the root and new root's parent be null
– 3) currNode == root and currNode.right == null
– make root.left be the root and new root's parent be null
Delete a key in a BST• There are several cases to consider
– 4) currNode != root and currNode.left == null
– Make currNode's parent now point to currNode.right• Change parent's left or right depending on whether currNode was the left or right child
– 5) currNode != root and currNode.right == null
– Make currNode's parent now point to currNode.left• Change parent's left or right depending on whether currNode was the left or right child
Delete a key in a BST• There are several cases to consider
– 6) currNode == root and both right and left are not null– 7) currNode != root and both right and left are not null– These are the hard ones because the node to delete has two children.
We need to maintain the properties of the BST after deletion.– We'll look at the left subtree of currNode and find it's rightMost node,
store it in lstrmn (left subtree's rightmost node).– Then we can
• a) set currNode.key = lstrmn.key• b) remove the node lstrmn from the tree by calling
removeRightmost(currNode)
– Which means to remove the RM node in the subtree that has currNode as the root
• Let's talk about fixing removeRightmost (to handle arbitrary subtrees) –
you'll do it in lab tomorrow
Allowing duplicate values• One way to allow duplicate values in our BST, is the way we
already discussed --- which is if a key < some key then it lives
on the left side of it. If the key is >= some key then it lives on
the right side.
• Another way would be to change the BSTNode to contain a
count value which describes how many are in the tree.
• When you want to add a node with a key that already exists,
instead of inserting the new node, just ++ the count of that
node. To delete, decrement the count. When it gets to 0,
remove the node completely.
Allowing duplicate values• I'll let you make the required changes to our code to handle
dups in this way in lab tomorrow.
• How will this idea effect traversals? What about changeKey ?
implement sizeOf method• The sizeOf method will take in a node r and return the number
of nodes that are in the subtree that has r as a root.
public int sizeOf(BSTNode r){
// any ideas?
}
Again ... implement this during lab tomorrow.
implement BSTree as an array• Another thing you'll do during lab tomorrow is to implement
the BST as an array. Do we recall how that worked?
Recursion
• 1. have at least one base case that is not recursive• 2. recursive case(s) must progress towards the base case• 3. trust that your recursive call does what it says it will do
(without having to unravel all the recursion in your head.)• 4. try not to do redundant work. That is, in different
recursive calls, don't recalculate the same info.
Recursion
• some definitions are inherently recursive• e.g.• sum of the first n integers, n>= 1.• S(1) = 1• S(N) = S(N-1) + N
• recursive code for this• iterative code for this• simpler code for this (based on our proof) N*(N+1)/2• any problems with the recursive code? n=0 or large n?
Recursion
• The last example showed that recursion didn't really simplify our lives, but there are times when it does.
• e.g. If given an integer and you wanted to print the individual digits in order, but you didn't have the ability to easily convert an int >10 to a String.
• e.g. int n=35672;• If we wanted to print 3 first then 5 then 6 then 7 then 2,
we need to come up with a way to extract those digits via some mathematical computation.
• It's easy to get the last digit n%10 gives us that. • Notice: 35672 % 10 = 2 also 2 % 10 = 2.• Any ideas on a recursive way to display all the numbers in
order?
Recursion
void printDigits(int n){
if (n>=10)printDigits((n/10));
System.out.println( n%10 );}
// what's the base case here?
// what's the recursive step here? Will it always approach the base case?
Recursion
• Now that last problem was made up sort of, because Java (and most languages) allow us to print ints.
• However what if we wanted to print the int in a different base? Say base 2, 3, 4, 5, or some other base?
Recursion
• The fibonacci sequence is:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
– Can you detect the pattern?
Recursion
• The fibonacci sequence is:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
• Fibonacci numbers are simply defined recursively:F
0 = 0
F1 = 1
Fn = F
n-1 + F
n-2
• How could we convert this to code to calculate the ith fibonacci number?
Recursion• Fibonacci numbers are simply defined recursively:
F0 = 0
F1 = 1
Fn = F
n-1 + F
n-2
• How could we convert this to code to calculate the ith fibonacci number?int fib(int i){
if (i <= 1)return i;
elsereturn ( fib(i-1) + fib(i-2) );
}
Recursionint fib(int i){
if (i <= 1)return i;
elsereturn ( fib(i-1) + fib(i-2) );
}
Any problems with this code?
Recursionint fib(int i){
if (i <= 1)return i;
elsereturn ( fib(i-1) + fib(i-2) );
}
Any problems with this code?Yes – it makes too many calls. And further, these calls
are redundant.It violates that 4th idea of recursion stated earlier: in
different recursive calls, don't recalculate the same info.
Top Related