CS2102 B2006 Exam #2

Q1. [12 pts.]

Given a base class B, a derived class C, and a method m of the derived class C:

a) Method m is an overloaded method. Explain what this means in relation to either class B or C.

For m to be an overloaded method, there must be another method in the same class with the same name, but different signature (i.e., parameter list). This method could be a static method in C, an instance method of C, or a non-private instance method inherited from B.

+2 There exists another method named m in C
+4 That method has a different signature than the m above.


b) Method m overrides another method. Explain what this means in relation to either class B or C.

For m to override another method, there must be a non-private instance method in the base class B with the exact same name, same method signature. If these conditions hold, then m overrides B's method m.

+2 There is another instance method named m in B that is non-private
+4 the method signature of m in B is identical to the method signature of m in C


Q2. [25 pts.]

You are given the following definitions (all classes belong to the same package).

Assume each class has a no-argument constructor. Assume you already have constructed the following two objects:

BusinessItem bi = new BusinessItem ();
Draw d = new Draw();

Which of the following five statements are legal? For the illegal statements only, explain why the statement is illegal:

S1. BusinessItem bi = new Item (); Illegal because Item is not a derived class of BusinessItem
S2. boolean b = d.equals(bi); Legal (because the .equals() method in java.lang.Object is inherited
S3. Object o = new Command(); Illegal because Command is an abstract class
S4. Command c = new Draw(); Legal because Draw is a derived class of Command
S5. Command c = new Item(); Illegal because Item is not a derived class of Command


Q3. [25 pts]

Design a RationalNumber class that represents fraction values n/d where n and d are integers > 0. You must define the following constructor and four instance methods. No Documentation is Necessary. Each of the following methods is 5 pts.

/** Represents a Rational Fraction n/d where n and d are integers > 0. */
public class RationalNumber {
   private int n; /** The numerator. */
   private int d; /** The denominator */
 

public RationalNumber (int n, int d) {
   this.n = n;
   this.d = d;
}
+ 2 public RationalNumber
+1 int n, int d as parameters
+2 updates instance appropriately
public boolean equals (Object o) {
  if (o == null) {
    return false;
  }

  if (o.getClass() == getClass()) {
     RationalNumber rn = (RationalNumber) o;
     return n * rn.d == d * rn.n
  }

  return false;
}

+2 public boolean equals (Object o)
+1 prevent null comparison and cast clash. Also could have used (o instanceof RationalNumber) instead
+1 Return false if type is wrong.
+1 Proper check. Could have used return (n == rn.n && d == rn.d); Note that the private data fields rn.n and rn.d are in fact visible within the equals method, because that object belongs to the RationalNumber class, and thus the values can be extracted within the equals method, which is executing on another RationalNumber object.

 

public void add (RationalNumber rn) {
  n = n * rn.d + d * rn.n;
  d = d * rn.d;
}
+3 Signature of public void add (RationalNumber rn)
+1 Proper calculation for numerator
+1 Proper calculation for denominator
public void multiply (RationalNumber rn) {
    n *= rn.n;
    d *= rn.d;
}
+3 Signature of public void multiply (RationalNumber rn)
+1 Proper calculation for numerator
+1 Proper calculation for denominator
public String toString() {
   return n +"/" + d;
}
+3 Signature of public String toString()
+2 Proper format

Q4. [22 pts.]

Given the following NumberNode and NumberList classes and an add (int i) method in NumberList that prepends numbers to the linked list start with head.

/** Node class representing an integer. */
public class NumberNode {
  int          value;    /* node value. */
  NumberNode   next;     /* next one. */

  public NumberNode (int i) {
    value = i;
    next = null;
  }

/** List of numbers. */
public class NumberList {
  NumberNode head;  /* first one. */

  public void add (int i) { … }
}

Write an instance method collapse for NumberList that removes all sequential repetitions of numbers in the list starting with head. For example, consider the NumberList resulting from: add(5); add(1); add(1); add(1); add(4); add(2); add(2), represented by {2, 2, 4, 1, 1, 1, 5}. After calling collapse on this NumberList object, the list becomes {2, 4, 1, 5}.

(a) [16 pts.] Implement the collapse method. Provide No Documentation.

Several Solutions Points Description
public void collapse() {
   if (head == null) { return; }

   NumberNode node = head;
   while (node.next != null) {
      if (node.next.value == node.value) {
         node.next = node.next.next;
      } else {
         node = node.next;
      }
   }
}

+3 public void  collapse() { ... }
+2 NumberNode node;    // creating a variable to traverse the loop. Can't just use head
+2 use a while or a for loop.
+1 use condition (node.next != null) in the while loop
+2 compare neighbor node values using ==
+3 Unlink duplicate node when needed
+3 Advance but only if not equals
// pattern after remove

public void collapse() {
   if (head == null) { return; }

   if (head.next == null) { return }

   NumberNode prev = head;
   NumberNode next = prev.next;
   while (node != null) {
      if (prev.value == node.value) {
         prev.next = node.next;
      } else {
         prev = prev.next;
      }

      node = node.next;
   }
}

 

Same grading system applies
// Twisted, but sweet

public void collapse() {
   NumberNode last = head;
   NumberNode cur = head.next;
   while (cur != null) {
      if (cur.value != last.value) {
          last.next = new NumberNode(cur.value);
          last = last.next;
      }
      cur = cur.next;
    }
    last.next = null;
}

See if you can figure out why this works.
// Nested loop solution

public void  collapse() {
    NumberNode node = head.next;
    NumberNode prev = head;

    while (node != null) {

         // process potential sequence
         while (node != null && node.value == prev.value) {
             node = node.next;
             pre.next = node;
         }

         pre = node;
         node = node.next;
     }
}

 


(b) [6 pts.] Explain why the collapse method should in NumberList and not NumberNode.
 

The NumberList class represents the concept of a link list, and operations (such as add) that affect the linked list should be placed in that class. The NumberNode class represents a single link in the chain. Thus, having the collapse() method in NumberNode breaks encapsulation. There is a more pertinent reason, too. If you call collapse() on a NumberNode that is in the middle of a list, then you will only be collapsing part of the list (i.e., the tail end, rather than the front part).

+5 Collapse is intended to remove duplicate sequences from a List not a node
+1 If this were in node, then you would be of too limited scope and may end up with a List that still has repetition sequences


Q5. [14 pts] These questions use the NumberNode and NumberList classes, shown again above.

(a) [6 pts.] If the value and next instance variables in NumberNode were changed to be private instance variables, explain the changes you would need to make to the NumberNode class.

Traversing a linked list requires access to the value (both setting it and retrieving it) and to the next reference (both setting and getting). Thus making the variables private means we must provide these methods (accessors and mutators) ourselves:

public int getValue() { return value; }
public void setValue(int i) { this.value = i; }
+2 points. Note that setValue isn't really needed; provided for completeness
public void setNext(NumberNode n) { this.next = n; } +2 points
public NumberNode getNext() { return next; } +2 points



(b) [8 pts.] The following method void strangeMethod() exists in the NumberList class. After it is invoked on a NumberList object, what is the resulting linked list maintained by that object?

public void strangeMethod() {
  head = new NumberNode(3);      // S1
  NumberNode node = head.next;   // S2
  node = new NumberNode(5);      // S3
  node.next = head;              // S4
}

 

Note how we simply execute these statements one at a time. S1 creates a NumberNode representing 3 whose next reference is null. S2 sets the value of node to be null since the head node points nowhere; S3 creates a new node representing 5. Now head points to the node whose value is 3 while node points to the node representing 5. S4 sill have node point to the original node pointed to by head.

Now: Here is the relevant piece of information. The question is asking for "the resulting linked list maintained by that object" (in other words) the list on which this method is invoked. Now, we see that the linked list must be considered a list of size 1, with the first (and only) node in the list being the NumberNode representing 3. While there is/was a node variable that pointed to a NumberNode whose next pointed to head, that object is irrelevant from the perspective of the NumberList class.

Showing your work +2 points
A linked list with a single NumberNode that maintains the int value 3 +4
If two elements in list -2 points


Q6. [2 pts.] Fill in the Dilbert cartoon. If my eyes burn from the radiance of your joke, you get extra points. Or, list the name of one of the classical music selections from the daily objectives.