CS 201 - Exam 2 - 11/14/2018

DUE: Wednesday, 11/21, at 11:59pm

This is the second of two midterm exams. Like the first one, it will count 15% towards your final grade; however, this exam is a one-week take-home exam in place of the weekly homework. There are no afternoon labs and no evening tutoring sessions during the period of the exam.

The exam has 8 problems. Problems 1-5 are programming problems; problems 6-8 are written problems. The number of points for each problem appears in brackets next to the problem. There are 100 points total on the exam. All programming problems contribute to the same applet, and you can do them in any order, though they appear roughly in order of increasing difficulty.

The exam is open book in the sense that you can consult any books, handouts, or notes from this class to solve the problems. You may also follow the links from the course page and this exam 2 page to directly linked materials, e.g., the Java API and linked Wikipedia pages. However, you may not do any web searches, for instance to find answers on online discussion boards. You may not look at any code, except for the code examples from the course web page and the textbook. Also, you may not consult material or solutions from previous semesters or try to gain access to the source code for sample applets. I am the only person you may talk to about the exam. You may not consult or collaborate with other students or tutors. I will clarify the problems if you have trouble understanding them, but because this is an exam, I cannot help you solve the problems. If you are stuck, definitely come see me -- I can at least give general problem-solving advice.

Please be very careful to protect your work from the access of others.

Turning in this Exam

You will turn in the code for this exam electronically as usual. For the written problems, you have two options: you can either write them on paper, and submit them in class or to my office; or, you can type them in a word processor and upload them as a PDF file. Since some of the written problems require you to draw trees, doing the paper submission might be easier. If you choose to upload your written answers, be sure to follow these rules, otherwise you will lose points: Please submit your code (and optionally your PDF) using the Exam2 submission page.

The deadline for both submissions Wednesday 11/21 at 11:59pm. This is a hard deadline. You cannot turn in the exam later than this time, and you cannot use one of your 24 h extensions. Even if you are not finished with the exam by this time, you should turn in what you have, so that I can award partial credit. If a program does not work completely, it would be helpful if you included comments that describe what aspects of your program do and don't work. Be sure that your code at least compiles, otherwise you will likely receive a failing grade on the programming portion.


K-d Trees

The programming problems on this exam involve K-d trees a data structure used to organize points in K dimensions. Here's a Wikipedia page, which you may look at, including the code listed on that page (but recall any other code on the web is off limits).

In this exam (and the description below), we only consider K=2 dimensions, a set of points in the 2D plane.

A K-d tree is a binary search tree. Each node stores a 2D point (x, y), which serves as a "splitting point" for the remaining points in the subtrees. Either the x or y coordinate is used for splitting, alternating by level. At the root (level 0) we use the x coordinate, at level 1 the y coordinate, at level 2 the x-coordinate again, and so on. (For higher-dimensional K-d trees, one rotates through all dimensions by level, e.g., x, y, z, x, y, z, ...)

Here's a snapshot of the exam 2 applet in action, with hand-drawn annotations:

On the left we see an arrangement of four points in the plane as well as their splitting lines; on the right we see the corresponding binary tree. X-nodes are shown in blue, y-nodes in red. The green hand-drawn arrows indicate how nodes on the right correspond with points on the left. The root node corresponds to the point with coordinates (66, 118). It is an x-node (dark blue), thus all points in the left subtree have x-coordinates <= 66, and all points in the right subtree have x-coordinates >= 66. On the left, this is visualized with the dark blue vertical line extending all the way from the top to the bottom.

Now, consider the children of the root node on level 1, which are y-nodes (dark red). For instance, the right child corresponds to the point with coordinates (217, 198). Since it is a y-node, all points in the left subtree have y-coordinates <= 198 (here there aren't any), and all points in the right subtree have y-coordinates >= 198. Again, on the left this is visualized with lines, this time dark red and horizontal; note that they extend from the edges to vertical "root line". Note that for y-nodes, the left subtree (with smaller y values) corresponds to the region above the line, and the right subtree to the region below the line.

Next, on level 2 we only have one node, an x-node again, and its (blue) vertical splitting line ends at the horizontal "parent line".

Play with the sample applet below (or with this bigger version) to get a feel for how the arrangement of points on the left corresponds to the tree on the right. Problems 1-5 on this exam involve adding code to a skeleton file to create an applet that functions like the one shown here. Additional information on how the applet functions is given in the problem descriptions.

Your browser does not appear to support applets.

Recall that you can run any applet in the appletviewer by providing the URL of the page containing the applet. To do so for the sample exam applet, type


appletviewer http://www.cs.middlebury.edu/~schar/courses/cs201-f18/hw/exam2/
All files required for this exam are contained in the file exam2.zip. Unzip this file in your cs201 directory. The resulting directory exam2 will contain the following files:
    KdTree.java       - the definition of the K-d tree
    KdTreeApplet.java - the actual applet
  * KdTreeOps.java    - operations on K-d trees
    Point.java        - a simple 2D point class
    PointCanvas.java  - the left portion of the applet, rendering points and lines
    TreeCanvas.java   - the right portion of the applet, rendering the tree
    kdapp.html        - an html file to run the applet
The only file you have to modify is marked with a star. However, you should study the other files as well, in particular KdTree.java and Point.java. The KdTree class is similar to the IntTree class, but each node stores a point and a boolean "isX" keeping track of whether it's an x-node or a y-node. The minimal Point class has public instance variables x and y allowing direct access, as well as a useful instance method coord(boolean isX) that retrieves one of x and y depending on whether isX is true or false.

Import the exam2 directory into Eclipse as usual. The code provided compiles and runs. You can run it from within Eclipse by opening KdTreeApplet.java and selecting "Run As -> Java Applet", or from the command line using:

    javac KdTreeApplet.java
    appletviewer kdapp.html
After running it once from Eclipse, I suggest you change the applet size to width 1000 and height 600 (Run -> Run Configurations -> Parameter tab).

Start by adding your name to the top KdTreeOps.java (expand the comment at the top). Initially, many parts of the applet are not yet functional. As you are completing the programming problems, more functionality will be added piece by piece, which allows you to test your code for each problem thoroughly before moving on to the next problem. Be sure your code compiles at all times!


Problem 1 [10]: Counting nodes

Complete the method countNodes in KdTreeOps.java, which is supposed to count all the nodes of the correct type (x-nodes or y-nodes, depending on whether the parameter "isX" is true or false). Some of this code will look very similar to the IntTree code, but note that we don't provide static methods, so for instance you have to use t.left() instead of left(t), and t == null instead of isEmpty(t).

Once your methods work, the node counts displayed above the tree should be correct.


Problem 2 [10]: Checking whether the tree is symmetric

Complete the method isSymmetric in KdTreeOps.java. It should return whether left and right subtrees of the tree have shapes that are mirror images of each other. This will require writing a helper method that takes takes two trees as parameters and recursively checks whether they are mirror images of each other. Hint: one of the problems on HW 6 solves a very similar problem.

Once your methods work, the text displayed above the tree should correctly indicate whether the tree is symmetric.


Problem 3 [15]: Computing the width of trees

Complete the methods width, leftWidth, and rightWidth in KdTreeOps.java. This methods are used for variable-width tree drawing, which you can select from the pull-down menu underneath the tree.

We compute the width of a tree by measuring the width of an (imaginary) picture of the tree which is drawn according to the following rules: All nodes are drawn as circles with radius 1. To draw a tree, we draw the circle for the root, and then each of the two subtrees below such that they touch the vertical line through the center of the root circle (from the left and the right, respectively). Some trees and their widths are shown below:

It can be seen that the following rules apply: The left width of a tree is the width of the part of the tree left of the vertical line through the center of the root. It can be seen that The right width is defined analogously.

Note that some of the above rules are redundant. Try to define the each function in terms of the others as succinctly as possible.

Once your methods work, the tree drawn with "variable" drawing style should match the way it is drawn in the sample applet. (Note that the drawing code, which you can find in TreeCanvas.java, multiplies the values returned by your functions with radius of the node circles to determine the proper spacing.


Problem 4 [15]: Drawing the splitting lines

Complete the method draw in KdTreeOps.java. This method is called from the paint method in PointCanvas to draw the arrangement of points and lines on the left side of the applet. The code initially provided ignores the parameters x0, y0, x1, y1 that specify the size of the region in which to draw, and instead only draws short line segments centered around each point. Change the marked lines of code so that the red and blue lines extend all the way to the edges of the region, and also provide the correct values for these parameters in the recursive calls.

Once your methods work, the drawing on the left side of applet should match that of the sample applet.


Problem 5 [15]: Rebuilding a balanced tree

Complete the methods collectPoints and buildKdTree in KdTreeOps.java. These methods are called from the rebuild method to rebuild the tree from scratch, balancing the sizes of the subtrees in the process. The following strategy is employed: First, all points in the old tree are added to a vector of points using a traversal of the tree via the (very simple) collectPoints method. For full credit you should write this method such that it performs a pre-order traversal (though the actual order of traversal doesn't matter since the vector will get sorted later anyway). Next, apply the following recursive strategy for converting a portion of the vector (with indices start .. end-1, where start is initially 0 and end is initially the length of the vector): Some of the code is already given for you, in particular sorting of a portion of the vector; you have to fill in the rest.

Once your methods work, clicking the "Rebuild" button should balance the tree and change the arrangement of the splitting lines, but should not affect the number and location of the points. Again, compare with the behavior of the sample applet to make sure your methods work correctly.

Written problems

You can submit your written answers on paper or electronically; see instructions above.


Problem 6 [12]: Complexity of tree and heap operations

What is the worst-case time complexity of each of the following operations? Give your answers in big-O notation and include brief justifications. In case a data structure doesn't normally support the operation, describe how it could be implemented and still give its complexity. For questions relating to heaps, assume min-heaps (as in the book and our examples). Include the answers with your written submission.
  1. Finding the smallest number in a skew heap of N integers
  2. Adding an new number to a complete heap of N integers
  3. Finding the largest number in a complete heap of N integers
  4. Finding the smallest number in a complete binary search tree containing N integers
  5. Finding the largest number in an arbitrary binary search tree containing N integers
  6. Checking whether a given number is contained in an AVL tree containing N integers


Problem 7 [13]: Tree drawing

Include the drawings and answers to the following questions with your written submission.
  1. Draw all complete heaps containing the five values 1, 2, 3, 3, 4. (Note the duplicate 3!) How many are there?

  2. Draw all complete binary search trees containing the six values 1, 2, 3, 4, 5, 6. How many are there?

  3. Draw all full, ordered 2-3 trees containing the eight values 1, 2, 3, 4, 5, 6, 7, 8. How many are there?

  4. Draw all ordered AVL (i.e., balanced) trees containing the five values 1, 2, 3, 4, 5. How many are there?


Problem 8 [10]: Tree traversals

The solution to the extra-credit problem on homework 6 used a queue to print out the nodes of a tree in level-order:
    public static void levelOrderWrite(IntTree t) {
        // prints out the contents of the tree t in level order
        Queue<IntTree> q = new QueueList<IntTree>();
        q.add(t);
        while (!q.isEmpty()) {
            IntTree node = q.remove();
            if (!isEmpty(node)) {
                System.out.print("  " + value(node));
                q.add(left(node));
                q.add(right(node));
            }
        }
        System.out.println();
    }
What would happen if you replaced the queue with a stack? List the order in which the values of the following tree would get printed:

In general, would all nodes in the tree get printed? If yes, in what order? Justify your answer. (You are welcome to try it out, but you'll have to explain your findings - simply stating what happens is not enough.) Include your answer with your written submission.


Good Luck!