Loyola College in Maryland

CS 202 - Computer Science II
Fall 2004


Loyola College > Department of Computer Science > Dr. James Glenn > CS 202 > Homework > Final Exam Practice

Problem 1: Assume that the given class definitions are in the appropriate files. There are 16 statements below the comment in main, which is in the SubC class. Some of those 16 statements are illegal. Cross out the illegal statements and indicate whether they cause a compiler error or a runtime error.. Give the output of the remaining statements (ignore the effects of any illegal statements). Some legal statements may produce no output.

abstract public class Super {
    abstract public void kick();
    public void pass() {System.out.println("Super.pass");}
    private void tackle() {System.out.println("Super.tackle");}
}

public class SubA extends Super {
    public void kick() {System.out.println("SubA.kick");}
    public void pass() {System.out.println("SubA.pass");}
    public void punt() {System.out.println("SubA.punt");}
}

public class SubB extends Super {
    public void kick() {System.out.println("SubB.kick");}
    public void punt() {System.out.println("SubB.punt");}
}

public class SubC extends SubA {
    public void kick() {System.out.println("SubC.kick"); super.kick();}
    public static void main(String[] args) {
        SubA one = new SubA();
        SubB two = new SubB();
        Super three = new SubC();

        // Some of these statements may cause errors at compile- or run- time.

        one.kick();
        one.pass();
        one.punt();
        one.tackle(); // tackle is private

        two.kick();
        two.pass();
        two.punt();
        two.tackle(); // still private

        three.kick();
        three.pass();
        three.punt(); // three declared as Super; punt not declared in Super
        three.tackle(); // funny how some things don't change

	SubA four = (SubA)two; // no ancestor/descendant relationship
	SubA five = (SubA)three;

        three = new Super(); // Super is abstract
        two = three; // 
        three = one;
        three.pass();
    }
}

All of the errors were compiler errors. The output is given below.

SubA.kick
SubA.pass
SubA.punt
SubB.kick
Super.pass
SubB.punt
SubC.kick
SubA.kick
SubA.pass
SubA.pass

Problem 2: Write an applet that has two text fields and a button. One of the text fields is used for user input. The other is used to display the total of the numbers the user has entered. The total starts at zero and is updated each time the user clicks the button. The applet should display an error message if the user enters a non-numeric value.

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class AddingMachine extends JApplet implements ActionListener
{
    private JTextField inputField;
    private JTextField outputField;
    private JLabel statusLabel;
    private double total = 0.0;

    public void init()
    {
        // make a panel to hold the text fields

        JPanel textPanel = new JPanel(new GridLayout(2, 2));

        inputField = new JTextField();
        textPanel.add(new Label("Input:"));
        textPanel.add(inputField);

        outputField = new JTextField("0.0");
        outputField.setEditable(false);
        textPanel.add(new Label("Total:"));
        textPanel.add(outputField);

        // make a panel to hold the button and status

        JPanel bottomPanel = new JPanel(new BorderLayout());

        // put the button in another panel so it won't get stretched

        JPanel buttonPanel = new JPanel();
        JButton addButton = new JButton("Add");
        addButton.addActionListener(this);
        buttonPanel.add(addButton);

        statusLabel = new JLabel(" ");

        bottomPanel.add(buttonPanel, BorderLayout.CENTER);
        bottomPanel.add(statusLabel, BorderLayout.SOUTH);

        // put the panels in the applet

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(textPanel, BorderLayout.CENTER);
        getContentPane().add(bottomPanel, BorderLayout.SOUTH);
    }

    public void actionPerformed(ActionEvent e)
    {
        try
            {
                // read user input and add to total

                total += Double.parseDouble(inputField.getText());

                // display new total

                outputField.setText(String.valueOf(total));

                // clear any error message

                statusLabel.setText(" ");
            }
        catch (NumberFormatException ex)
            {
                statusLabel.setText("Please enter a number");
            }
    }
}

Problem 3: Write a method called tail that takes three arguments: the name an input file, the name of an output file, and the number of lines to copy from the end of the input file to the output file. For example, if the input file contains

Joanna: So where do you work, uh, Peter?
Peter: Initech
Joanna: And, uh, what do you do there?
Peter: I sit in a cubicle and I update bank software for the 2000 switch.
Joanna: What's that?
and the last argument was 2 then the output file should contain
Peter: I sit in a cubicle and I update bank software for the 2000 switch.
Joanna: What's that?
One way to do this without creating a list to hold the entire file is to use a queue. As you read lines from the input file, put them on back of the queue. If the queue is then bigger than the number of lines required, remove a line from the front of the queue. Once the end of the file has been reached, the method could output each line in the queue.
public static void tail(String input, String output, int howMany)
{
    // make a queue to hold the last howMany lines read

    LinkedList q = new LinkedList();

    try
        {
            // open the input file

            BufferedReader infile
                = new BufferedReader(new FileReader(input));

            // read to end of file

            String line;
            while ((line = infile.readLine()) != null)
                {
                    // save line in last howMany read

                    q.addLast(line);
                        
                    // remove line read howMany+1 ago

                    if (q.size() > howMany)
                        q.removeFirst();
                }
           }
   catch (IOException e)
       {
           System.err.println("Error reading " + input);
       }

   try
       {
           // open the output file

           PrintWriter outfile = new PrintWriter(new FileWriter(output));
                
           // output all strings on the queue

           while (q.size() > 0)
                outfile.println(q.removeFirst());

           // close the output file

           outfile.close();
        }
   catch (IOException e)
       {
           System.err.println("Error writing " + output);
       }
}

Problem 4: Write a method that takes as its parameter a string containing a Windows path and file name, for example "C:\Documents and Settings\All Users\Desktop\Calendar.java". The method should output, using System.out.println, all of the subdirectories in the path. For the above example the output should be three strings

Documents and Settings
All Users
Desktop
public static void pathToList(String path)
{
    // break path up based on backslash (\\ stands for a single backslash)
    
    StringTokenizer tok = new StringTokenizer(path, "\\");
    
    // throw away drive specification
    
    if (tok.hasMoreTokens())
        tok.nextToken();
    
    // go through the rest of the tokens, remembering the previous one
    
    String last = null;
    
    while (tok.hasMoreTokens())
        {
            // save the previous token on the list
            
            if (last != null)
                System.out.println(last);
            last = tok.nextToken();
        }
    
    // since the last token (the filename) is no other token's previous
    // token, it has not been saved
    
    return result;
}

Problem 5: Redo problem 2, but return the subdirectory names in a List object instead of printing them to the screen.

public static List pathToList(String path)
{
    // make an empty list to hold the subdirectory names
    
    List result = new LinkedList();
    
    // break path up based on backslash (\\ stands for a single backslash)
    
    StringTokenizer tok = new StringTokenizer(path, "\\");
    
    // throw away drive specification
    
    if (tok.hasMoreTokens())
        tok.nextToken();
    
    // go through the rest of the tokens, remembering the previous one
    
    String last = null;
    
    while (tok.hasMoreTokens())
        {
            // save the previous token on the list
            
            if (last != null)
                result.add(last);
            last = tok.nextToken();
        }
    
    // since the last token (the filename) is no other token's previous
    // token, it has not been saved
    
    return result;
}

Problem 6: Write a recursive method that computes ak, where ak is defined as follows: a0 = 2, a1 = 1, and ak = 2ak-1 + ak-2 for k > 1.

public static int a(int k)
{
    if (k < 0)
	throw new IllegalArgumentException();
    else if (k == 0)
	return 2;
    else if (k == 1)
	return 1;
    else
	return 2 * a(k - 1) + a(k - 2);
}

Problem 7: Consider the following recursive function (taken from the solutions for the last practice set).

public int w(int k)
{
  if (w == 0)
    return 2;
  else if (w <= 3)
    return 1;
  else if (w(k - 1) == 1 && w(k - 2) == 1 && w(k - 3) == 1)
    return 2;
  else
    return 1;
}
Draw the recursion tree for the call w(5). What value does w(5) return? What value does w(7) return?

          w(5)
       /    |   \
   w(4)    w(3)    w(2)
 /   |   \
w(3) w(2) w(1)

w(5) and w(7) both return 1.


Problem 8: Write a recursive function that takes as its parameter a Node in a binary search tree and returns the height of the subtree starting at that node, where the height is defined to be the number of nodes on the path to the deepest leaf, so an empty tree has height 0 and a tree with only one node has height 1. (Hint: the height of the subtree starting at a node is one more than the taller of the two trees starting at its children.)

public int height(Node n)
{
  if (n == null)
    return 0;
  else
    return 1 + Math.max(height(n.left), height(n.right));
}
or, for a more object-oriented approach, add the following to the Node inner class (so we would call n.height() instead of height(n)):
public int height()
{
  if (left == null && right == null)
    return 1;
  else if (left == null)
    return 1 + right.height();
  else if (right == null)
    return 1 + left.height();
  else
    return 1 + Math.max(left.height(), right.height());
}

Problem 9: The following code displays all the items on a List called l. What is the big-Oh running time if the list is an ArrayList? What if the list is a LinkedList?

for (int i = 0; i < l.size(); i++)
  System.out.println(l.get(i));

For a linked list, get takes O(n) time; there are O(n) calls to get, so O(n * n) = O(n2) time total. For an array-based list, each get takes O(1) time, and the number of calls is still O(n), so O(1 * n) = O(n) time total.


Problem 10: Modify the existing code for TreeSet202 so that each Node has a reference to its parent in addition to its children (the root's parent should be null). Show the additions to the Node class definition and the add method.

We add a field to the inner class and allow that field to be initialized via the constructor:

private static class Node
{
    Comparable data;
    Node left, right, parent;
    
    private Node(Comparable d, Node p)
    {
        data = d;
        parent = p;
    }
}
We also add code to add so each new node knows where its parent is:
public boolean add(Object o)
{
    Comparable toAdd = (Comparable)o;
    
    Pair position = find(toAdd);
    
    if (position.child != null)
        {
            // already in the set
            
            return false;
        }
    else
        {
            if (position.parent == null)
                {
                    // adding 1st node
                    
                    root = new Node(toAdd, null);
                }
            else if (position.parent.data.compareTo(toAdd) > 0)
                {
                    // adding left child
                    
                    position.parent.left = new Node(toAdd, position.parent);
                }
            else
                {
                    // adding right child
                    
                    position.parent.right = new Node(toAdd, position.parent);
                }
            
            numNodes++;
            return true;
        }
}

Problem 11: Write a method that takes a node as a parameter and determines if that node is the right or left child of its parent using the parent reference added in problem 8. The method should return -1 if the node is a left child, 1 if it is a right child, and 0 if the node is the root.

public boolean whichChild(Node n)
{
  if (n.parent == null)
    return 0;
  else if (n.parent.left == n)
    return -1;
  else
    return 1;
}
or, thinking of this from an object-oriented point of view and writing a method in the Node class instead of a method that takes a Node as an argument:
public boolean whichChild()
{
  if (parent == null)
    return 0;
  else if (parent.left == this)
    return -1;
  else
    return 1;
}

Problem 12: Show the result of adding the strings "Twas", "The", "Night", "Before", "Christmas", "And", "All", "Through", "House", "Not", "A", "Creature", "Was", "Stirring" to a binary search tree in that order.


From Rod Howell's Search Tree Viewer

Problem 13: Put the strings from the previous problem in an array in sorted order. Which strings are compared when doing a binary search for "Christmas", "Was", and "Not"?

0 1 2 3 4 5 6 7 8 9 10 11 12 13
A All And Before Christmas Creature House Night Not Stirring The Through Twas Was