Game trees: make sure everyone understands the following. Say you have a finite game (guaranteed to end in some number of steps) that ends with a winner or a tie. Then either the first player has a winning strategy, or the first player has a strategy that forces at least a tie, or else the 2nd player has a winning strategy.
You may notice that sometimes the computer will make a move that leads to a pretty quick loss. This is not necessarily incorrect. If the computer realizes that all of its moves eventually lead to a loss, it may just pick one arbitrarily, which has the appearance of giving up. One interesting feature that you could add to your programs (if you wanted) is, when faced with an eventual loss, to pick the move that postpones losing as long as possible. Perhaps your opponent will make a mistake. Similarly, in case there are one or more winning moves, you might choose the one that wins quickest.
Today we're going to discuss a "Dictionary" Abstract Data Type with the following operations:
The first four operations are familiar. We've seen that they can be implemented in constant time (more or less) using hash table. They can also be implemented in O(log N) time using balanced search trees, where N is the number of elements in the tree when the operation is performed. You will learn how that is done in succeeding lectures. For now we'll just assume that it is true.
The members_in_range operation is new. It returns all of the values in the tree that lie between low_value and high_value. This is an example of an operation that is difficult to implement using hash functions. Why ought a tree be better for this?
We'll begin with an application: finding all of the intersections between the lines in a set of horizontal and vertical lines.
The input is a set of horizontal and vertical lines, specified by their endpoints. Consider a picture like the one below.
| | ---+------+---- | | | -+------+-----+--- | | | | | --+------------+--- | |The goal is to print out the coordinates of all of the intersections (ie, the + signs.)
Here's the algorithm that uses the members_in_range operation to do it:
As we scan from left to right, the tree contains the y-coordinates of all of the horizontal lines that intersect our sweep line.
How much time does this take?
Let N be the total number of lines. Step 1 will take O(N log N) time. Step 2 is more difficult to analyze. There are at most N insertions and N deletions, so the time spent on these operations is O(N log N). But we don't know how fast members_in_range is yet.
The inputs will be
You could make this a Tree member function if you wanted. The code would look something like this:
void
members_in_range(node *root, int low, int high, int xcoord) {
if(root == NULL) return;
if(root->value >= low)
members_in_range(root->left, low, high, xcoord);
if((root->value >= low) && (root->value <= high))
printout(root->value, xcoord);
if(root->value <= high)
members_in_range(root->right, low, high, xcoord);
}
It performs an inorder traversal of the tree, but doesn't explore branches where the values do not lie between low and high.
Try an example. How long does it take?
It will take O(log N + k), where k is the number of elements printed out. Why?
The search visits three types of nodes:
Well, the time is O(k + Nlog N), where k is the total number of intersections This is pretty good!