CS 2223 Nov 20 2015
Expected reading: 396-405
Daily Exercise:
Two roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood
And looked down one as far as I could
To where it bent in the undergrowth;
Robert Frost
1 Binary Search Trees
1.1 Exam1 returned today
Exam1 will be returned today. Here are the statistics:
avg 73.96 13.52 12.98 17.28 15.39 14.79 stdev 13.79 4.74 4.96 3.11 4.32 4.01 68% 65% 86% 77% 74%
(#29) 86 or higher – Doing Very Well. Think "A" grade. Keep it up!
(#38) 72 to 84 – Good Job. Think "B" grade
(#27) 60 to 70 – Needs Improvement. Think "C" grade
(#15) 58 or lower – At risk. Be sure to review progress and talk to me
1.2 BST Lecture
We will cover the fundamental data structure in computer science, called the Binary Search Tree (BST). This extremely versatile data structure gives us the dynamic behavior that you have seen with linked list while retaining the ~ log N search time we have seen for ordered binary array search.
In short, if you understand binary search trees, you know 50% of all the data structures used by computer science. It is that important.
We are going to stay here for awhile. Indeed, HW4 (to be released on Monday) will give you ample opportunity for you to demonstrate that you understand BSTs and can work with them on a practical and theoretical level.
1.3 Structure
The fundamental structure of a BST is a node in the tree. This node contains a (key, value) pair because the BST implements the Symbol Table API that we have already seen.
class Node { Key key; Value val; Node left, right; // left and right subtrees int N; // number of nodes in subtree public Node(Key key, Value val, int N) { this.key = key; this.val = val; this.N = N; } }
While it seems similar to a linear linked list, observe that there are two pointers from each node. With this extra information, we will be able to construct trees of information. We use the term tree because at no point will you be able to find a loop, much like how each linked list was guaranteed to terminate.
Here is a sample Binary Search Tree (BST):
The term tree may look odd, but this is how we draw trees in computer science. We start with the root at the top, and then grow downwards. Structurally, each node has up to two children.
The intuition behind BST is that we can structure values in specific ways to achieve impressive efficiencies.
1.4 Binary Search Tree property
The fundamental idea behind BST is that each node has potentially two subtrees, a left subtree and a right subtree. Given any node N in the BST, you are guaranteed that:
Each of the keys in the left subtree n.left are guaranteed to be smaller than or equal to n.key.
Each of the keys in the right subtree n.right are guaranteed to be larger than or equal to n.key.
1.5 Constructing a BST
You construct a BST by adding (key,value) pairs to it, one at a time. If the root of a tree is empty when you add the first node, then it must be created and it becomes the root of the tree. So in the above example, you should be able to guess that "S" was the first value entered into the tree.
The code for put requires some contemplation. There is a helper method put(parent, key, value) which adds a node representing (key,value) to belong to the tree rooted at parent.
If parent is null, then we create a new BST and return that as the BST.
Note that this means the helper put method returns a BST in all cases. In particular, this also means that if we were to add "E" as the second letter in the above BST, then parent would be the root. Since "E" is smaller than "S" we want to add this value to the left subtree. However, there is no left-subtree (yet) so it is created by the following code.
public void put(Key key, Value val) { root = put(root, key, val); } Node put(Node parent, Key key, Value val) { if (parent == null) return new Node(key, val, 1); int cmp = key.compareTo(parent.key); if (cmp < 0) parent.left = put(parent.left, key, val); else if (cmp > 0) parent.right = put(parent.right, key, val); else parent.val = val; parent.N = 1 + size(parent.left) + size(parent.right); return parent; }
We will spend time going over some examples.
1.6 Searching for value in BST
Searching is straightforward from the structure. We look for a value by starting at a parent node. If we have found it in that node, it is returned, otherwise we investigate either the left or the right branch, depending upon the relationship between the target key and the node’s key.
public Value get(Key key) { return get(root, key); } Value get(Node parent, Key key) { if (parent == null) return null; int cmp = key.compareTo(parent.key); if (cmp < 0) return get(parent.left, key); else if (cmp > 0) return get(parent.right, key); else return parent.val; }
1.7 Final BST thoughts
Get prepared to read the text and to work on lots of small examples. You need very up-close and personal experience with BSTs and that is going to be the focus for the next week.
1.8 Dominant Example
I added better documentation to the Dominant Example from Day13, and I encourage you to review it. Execute the code to see how well the actual performance compares with the predicted behavior.
1.9 Version : 2015/11/24
(c) 2015, George Heineman