CS365 Midterm -- Spring 2021


  1. (10 points: Event Handling) For each question below, look at the following list of items and fill in the blank with the best choice(s).
    JFormattedTextFieldJTableJSlider
    JRadioButtonJCheckBoxJButton
    JFrameJPanelJComponent
    JMenuJDialogJContainer

    1. JFrame The type of component used to create a Java window.

    2. JMenu The type of widget I should use to allow the user to select a state/territory in the United States. There are roughly 50 states/territories in the US.

    3. JFormattedTextField The type of widget to use when I want the user to enter a social security number with 3 digits, then a dash, then 2 digits, then a dash, and finally 4 digits.

    4. JTable The type of widget I should use to show a matrix of data with the rows representing a person and the columns representing information about the person, such as age, salary, name, etc.

    5. JLabel The type of widget to use if I want to convey a piece of information that should not be altered, such as instructions for entering some piece of data.

  2. (10 points: General content) For each question below, look at the following list of items and fill in the blank with the best choice(s).
    package       extends      import            virtual method
    interface     type         namespaces        generic
    class         finally      final             subtype
    public        Scanner      void              void *
    protected     subclasses   static            generational collector
    composition   inheritance  iterator          stop-and-copy collector
    Error         Throwable    Exception         RuntimeException
    IOException   event        interrupt         non-virtual method
    implements    classpath    include           hotspot compilation
    import        try          throw             reference counting
    catch         friends      polymorphism      mark-and-sweep collector
    Object        union        vtable            setjmp/longjmp

    1. C++ uses namespaces and friends to implement modules.
    2. void * C uses this type to implement generic types.
    3. vtable How virtual methods are implemented by the compiler.
    4. polymorphism The ability of the same code to perform the same action on different types of data.
    5. reference counting A type of garbage collector that explicitly counts the number of pointers to an object so that it can be garbage-collected when there are no longer any pointers to it.

  3. (25 points) Classes associated with the evaluation of expression trees. You need a top level class to represent a node in the tree and store the common items:
    abstract class ExpNode {
        OperatorNode parent;
        double value;
    
        public abstract double Evaluate();
        public double getValue() { return value; }
    }
    
    You might have given consideration to declaring Node as an interface but because it has implementation associated with it, it's better to declare it as an abstract class. It is able to provide a default implementation for getValue (I won't quibble if you declared it abstract) but it must declare Evaluate as pure virtual since every operator node will provide its own implementation. Since the parent is always an interior node, it is correct to declare it as an OperatorNode. I specifically asked you not to include the method bodies in your solution but I am doing so here to make it clear what the default implementations might look like.

    All operator nodes have an upToDate variable and use the same implementation for markCacheInvalid and getValue, so it is best to factor out this commonality into an OperatorNode class:

    	    
    abstract class OperatorNode extends ExpNode {
        boolean upToDate = false;
    
        final void markCacheInvalid() {
            upToDate = false;
            if (parent != null) { parent.markCacheInvalid(); }
        }
    
        final public double getValue() {
    	if (!upToDate) {
    	    Evaluate();
                upToDate = true;
            }
    	return value;
        }
    }
    
    Note that this class does not provide an implementation for Evaluate and hence it must be declared abstract. It also overrides the implementation for getValue and hence redeclares it here. I again have provided method bodies to make it clear why I am overriding ExpNode's implementation of getValue and why I am providing an implementation for markCacheInvalid in this class. Also note that I made both methods final as I do not want the subclasses to override their implementation.

    An Operand node is a concrete class that can implement the Evaluate method and provides its own SetValue method:

    	    
    class OperandNode extends ExpNode {
        public Operand(double val) { value = val; }
        public double Evaluate() { return value; }
        public void SetValue(double v) {
    	value = v;
    	parent.markCacheInvalid();
        }
    }
    
    There are three types of OperatorNodes and each of these 3 types will use the same constructor for setting up the children pointers, so it is best to factor this common constructor into three different operator node subtypes:
    abstract class UnaryOperatorNode extends OperatorNode {
        ExpNode child;
        public UnaryOperatorNode(ExpNode parameterNode) {
            child = parameterNode;
            child1.parent = this;
        }
    }
    
    abstract class BinaryOperatorNode extends OperatorNode {
        ExpNode child1;
        ExpNode child2;
        public BinaryOperatorNode(ExpNode param1, ExpNode param2) {
    	child1 = param1;
    	child2 = param2;
            child1.parent = this;
            child2.parent = this;
        }
    }
    
    // An NaryOperator node has two additional methods named addParameter and
    // removeParameter associated with it and this is common behavior that
    // should be factored into its class.
    abstract class NaryOperatorNode extends OperatorNode {
        ArrayList<ExpNode> children;
        
        public NaryOperatorNode(ArrayList<ExpNode>
     parameters) {
            children = parameters;
            for (ExpNode child : parameters) {
                child.parent = this;
            }
        }
        public void addParameter(ExpNode param) {
    	children.add(param);
        }
        public void removeParameter(ExpNode param) {
    	children.remove(param);
        }
    }
    
    These three classes are abstract because they cannot provide an implementation for the Evaluate method. I would not quibble if you made a binary operator node a subclass of a unary operator node since it is adding an additional child but would reuse the unary operator's child1 variable and constructor.

    Finally the PlusNode class is a concrete class that can implement the Evaluate method:

    	    
    class PlusNode extends BinaryOperatorNode {
        public PlusNode(ExpNode param1, ExpNode param2) {
    	super(param1, param2);
        }
        public double Evaluate() {
    	value = e1.getValue() + e2.getValue();
    	return value;
        }
    }
    
    Note that its constructor delegates the construction of the children pointers to the superclass constructor.

  4. (10 points: Packages) You have written a program named Appointment and placed it in a package named vaccine. vaccine is in a directory named /gov/tn and Appointment imports a package named gui that is located in a directory named /com/bvz.
    1. Write the java command required to execute Appointment. This command must work regardless of what directory you are in (i.e., you may not assume you are either in the parent directories for your packages or the package directories themselves).

      java -classpath .:/gov/tn:/com/bvz/ vaccine.Appointment

    2. Write the jar command required to jar up Appointment and allow the jar file to execute.

      You need to use the -C flag to "cd" to the appropriate directory and then grab the subdirectory's contents. If you write /gov/tn/vaccine or /com/bvz/gui, then the directories will be represented in the jar file as /gov/tn/vaccine and /com/bvz/gui and the java interpreter will be unable to locate the vaccine/gui directories because it is looking for directories name vaccine/gui and not /gov/tn/vaccine or /com/bvz/gui.

      jar -cef vaccine.Appointment Appointment.jar -C /gov/tn vaccine -C /com/bvz/ gui

  5. (20 points: Generics) Write a java generic class named Bag.
    class Bag<T1,T2> {
        List<T1> bag1 = new ArrayList<>();
        List<T2> bag2 = new ArrayList<>();
    
        public void add(T1 value1, T2 value2) {
    	bag1.add(value1);
    	bag2.add(value2);
        }
    
        public T2 find(T1 value) {
    	int index = bag1.indexOf(value);
    	if (index > 0)
    	    return bag2.get(index);
    	else
    	    return null;
        }
    }
    

  6. (25 points: Java Basics, Exception Handling) Write a java class named Vote that counts candidate names on ballots submitted by a voter and prints out the candidates' names in ascending order based on their vote count.

    You should use a HashSet to keep track of whether a voter has previously voted and a HashMap to tally the candidate's votes because each of these data structures requires O(1) time to locate a voter/candidate. If you use a SortedSet/Map then your finds will take O(log n) time and if you use an array or linked list, then your finds will take O(n) time. Once you have used the HashMap to tally the candidate's votes, you can dump the map's contents into an ArrayList and sort them into ascending order based on the candidates' vote totals.

    I have written this solution in the way that I presented the material in class. However, there are a couple ways to simplify the code:

    1. If you want to add 1 to the candidate's vote tally if the candidate already exists and otherwise insert the candidate and set the candidate's vote tally to 1, then the following single statement does the trick:
      voteTally.merge(candidateName, 1, Integer::sum);
      	      
      A longer but also very acceptable way to do it is:
      if (voteTally.containsKey(candidateName)) {
          voteTally.put(candidateName, voteTally.get(candidateName) + 1);
      }
      else {
          voteTally.put(candidateName, 1);
      }
      
    2. Map.Entry.comparingByValue() returns a comparator that will sort a Map in ascending order based on the type of its value so to sort the candidates in ascending order by vote count, you can first dump to map entries to an ArrayList and then execute the following statement:
      voteCount.sort(Map.Entry.comparingByValue());
      	      
    import java.util.*;
    
    class Vote {
        public class RepeatVoterException extends Exception {
    	public String voterName;
    	
    	public RepeatVoterException(String name) {
    	    voterName = name;
    	}
        }
    
        public static void main(String args[]) {
    	new Vote();
        }
    
        public Vote() {
    	Set<String> voterList = new HashSet<>();
    	Map<String, Integer> voteTally = new HashMap<>();;
    	String voterName, candidateName;
    	
    	Scanner console = new Scanner(System.in);
    	String line;
    	boolean readStartOfBallot = true;
    	
    	while (console.hasNextLine()) {
    	    line = console.nextLine();
    	    Scanner buffer = new Scanner(line);
    
                try {
                    // readStartOfBallot allows the exception handler to know
                    // whether I am processing the first part of the ballot with the voter's
                    // name and the first candidate's name or if I am processing the rest of
                    // ballot with the remaining candidates' names.
    		readStartOfBallot = true;
    		voterName = buffer.next();
                    candidateName = buffer.next();
    
                    // A set's add method returns true if the key is successfully
                    // added to the set and false otherwise
                    if (!voterList.add(voterName)) {
    		    throw new RepeatVoterException(voterName);
    		}
    
                    // read the remaining candidates until the list is exhausted.
                    // The Scanner class will throw a NoSuchElementException when
                    // the list is exhausted
                    readStartOfBallot = false;
                    while (true) {
                        voteTally.put(candidateName,
                                      voteTally.getOrDefault(candidateName, 0) + 1);
    		    candidateName = buffer.next();
    		}
    	    }
                catch (NoSuchElementException e) {
                    // ignore the exception if we have reached the end of the
                    // ballot
                    if (readStartOfBallot) {
    		    System.out.printf("ballot %s: must have at least one voter and one candidate%n", line);
    		}
    	    }
    	    catch (RepeatVoterException e) {
    		System.out.printf("voter %s has already voted%n", e.voterName);
    	    }
    	    finally {
    		buffer.close();
    	    }
            }
    
            // sort the candidate's in ascending order by their vote tally and
            // print their names/vote counts.
            List<Map.Entry<String, Integer>> voteCount = new ArrayList<>(voteTally.entrySet());
    
            voteCount.sort(new Comparator<Map.Entry<String, Integer>>() {
                public int compare(Map.Entry<String, Integer> e1,
    	                       Map.Entry<String, Integer> e2) {
                            return e1.getValue() - e2.getValue();
                }});
    
    	for (Map.Entry<String, Integer> votePair : voteCount) {
    	    System.out.printf("%s %d%n", votePair.getKey(), votePair.getValue());
    	}
        }
    }