return to lecture notes index

15-100 Lecture 32 (Monday, November 28, 2005)

Exam Solution

Today was basically a discussion of the recent exam. The solutions with some discussion follow

Question #1

As provided, the add(...) method failed if the underlying array was fully populated. It signified this failure by returning false.

Your task was to incorporate a call to the grow() method in order to allieveate this condition and allow the method to return only true.

This should have been easy -- replace the "return false;" with "grow();". Easy money!

  public boolean add(Comparable item) {

    if (count >= items.length)
      grow();
  

Question #2

Question #2 asks you to write a grow() method very similar to those that we create in class. The key difference between the form on the exam and those that we build in class is that, in class, the array doubled each time. Here it grows by exactly two. Again, easy money -- "2 * items.length" becomes "2 + items.length".

  public void grow() {
    Comparable[] biggerItems = new Comparable[items.length+GROW_AMOUNT];

    for (int index=0; index < count; index++) {

      biggerItems[index] = items[index];
    }

    items = biggerItems;
  }
  

Question #3

This question was really the bulk of the exam. But, with a little bit of thought, it falls easily. What are we asked to do? Return a subset of the container containing adjacent items within a particular range.

So, what we need to do is find the starting point and the ending point, and add everything in between to the new collection. But, there are three complications:

So, let's sketch our solution and then go from there:

  public OrderedContainer getNFrom (Comparable start, int n) {

    // Create the new container

    // Find the starting place, bail if none

    // Find the ending place, crop if beyond end

    // Copy the items into the new container

    // Return the new container
  }
  

Now, let's fill int the code to handle each of these small steps:

  public OrderedContainer getNFrom (Comparable start, int n) {

    OrderedContainer newContainer= new OrderedContainer(n);
   
    // Find the starting place, bail if none
    int startingIndex = getIndex(start);
    if (startingIndex == -1) return newContainer; // Found nothing

    // Find the ending place, crop if beyond end
    int endingIndex = start + n;
    if (endingIndex >= items.length)
      endingIndex = (items.length-1);
   
    // Copy the items
    for (int index=startingIndex; index <=; endingIndex; index++) {

      newContainer.add(items[index]);
    }
   
    // Return the new container
    return newContainer; 
  }
  

But, there's one last detail: The getIndex() method. I factored this out into a separate method for two reasons:

In the first iteration, I used a brute-force search:

  private int getIndex(Comparable item) {

    int startingIndex = 0;

    for ( ; startingIndex < count; startingIndex++) {
      if (items[startingIndex].compareTo(start) == 0)
        break;
    }

    if (startingIndex == count) 
      return -1;

    return startingIndex;
  }
  

But we can, of course, do better than this -- the list is ordered. The search is best iplemented as a binary search, as below:

  private int getIndex(Comparable item) {
    int left = 0;
    int right = count-1;
    int pivot = left + (right-left)/2;

    while (right >= left) {

      int difference = items[pivot].compareTo(item);

      if (difference == 0) return pivot;

      if (difference > 0)
        left = pivot-1;
      else
        right = pivot+1;

      pivot = left + (right-left)/2;
    }

    return -1;
  }
  

The Whole Thing

class OrderedContainer {


  private Comparable[] items;
  private int count;
  
  private static final int DEFAULT_SIZE = 2;
  private static final int GROW_AMOUNT = 2;
  private static final String NL = System.getProperty ("line.separator");
  
  
  public OrderedContainer () {
    count = 0;
    items = new Comparable[DEFAULT_SIZE];
  }
  
  
  public OrderedContainer (int size) {
    count = 0;
    items = new Comparable[size];
  }
  
  
  
  
  public String toString() {
    
    String retString = "Count: " + count + ", Length: " + items.length + NL;
  
    for (int index=0; index < count; index++) {
      retString += items[index] + NL;
   }
  
    return retString;
  }
  
  
  public int size() {
    return count;
  }
  
  
  /*
   * PROBLEM #1
   * MODIFY THIS METHOD
   *...so that it always returns true by growing
   */
  public boolean add(Comparable item) { 
  
    if (count >= items.length)

      grow();


      
   
    int hole = count;
    for ( ; hole > 0; hole--) {
      if (items[hole-1].compareTo(item) > 0)
        items[hole] = items[hole-1];
      else
        break;
    }
    
    items[hole] = item;
    count++;
    
    return true;
  }



  /*
   * PROBLEM #3
   * Complete this method so that it returns the _n_ items
   * beginning with the one provided (_start_), or nothing 
   * if start is not there.
   *
   * HINT: You may want a getIndex helper method...
   */
   

  private int getIndex(Comparable item) {
    int left = 0;
    int right = count-1;
    int pivot = left + (right-left)/2;
  
    while (right >= left) {
    
      int difference = items[pivot].compareTo(item);
    
      if (difference == 0) return pivot;
    
      if (difference > 0) 
        left = pivot-1;
      else
        right = pivot+1;
      
      pivot = left + (right-left)/2;
    }
    
    return -1;
    /* 
    int startingIndex = 0;
    for ( ; startingIndex < count; startingIndex++) {
      if (items[startingIndex].compareTo(start) == 0)
        break;
    }
    
    if (startingIndex == count) return -1;
    return startingIndex;
    */
  }

  public OrderedContainer getNFrom (Comparable start, int n) {

    OrderedContainer newContainer= new OrderedContainer(n);
    
    // Find the starting place, bail if none
    int startingIndex = getIndex(start);
    if (startingIndex == -1) return newContainer; // Found nothing

    // Find the ending place, crop if beyond end
    int endingIndex = start + n;
    if (endingIndex >= items.length)
      endingIndex = (items.length-1);
    
    // Copy the items
    for (int index=startingIndex; index <=; endingIndex; index++) {
      
      newContainer.add(items[index]);
    }
    
    return newContainer; // Found items
  }



 
  /*
   * PROBLEM #2
   * MODIFY THIS METHOD...
   * so that the container is grown by EXACTLY TWO elements
   */
  public void grow() {
  

    Comparable[] biggerItems = new Comparable[items.length+GROW_AMOUNT];
    
    for (int index=0; index < count; index++) {
    
      biggerItems[index] = items[index];
    }
    
    items = biggerItems;

  }


  public static void main (String[] args) {
    OrderedContainer oc = new OrderedContainer();

    System.out.println ("****************************");
    System.out.println ("***** THIS OUTPUT WILL NOT BE CONSISTENT UNTIL YOUR METHODS ARE CORRECT!");
    System.out.println ("****************************");
    System.out.println ("");
    System.out.println ("");

    System.out.println ("***** Testing grow by two...notice the growth by exactly 2.");
    System.out.println ("");
    
    System.out.println ("This container holds nothing (empty).");
    System.out.println ("Should be Count: 0, Length: 2");
    System.out.println (oc);
  
    System.out.println ("This container holds Apple, Banana, & Orange.");
    System.out.println ("Should be Count: 3, Length: 4");
    oc.add("Orange");
    oc.add("Apple");
    oc.add("Banana");
    System.out.println (oc);
  
    System.out.println ("This container holds Apple, Banana, Grapefruit, Orange, Pear, and Watermelon.");
    System.out.println ("Should be Count: 6, Length: 6");
    oc.add("Watermelon");
    oc.add("Pear");
    oc.add("Grapefruit");
    System.out.println (oc);

    
    System.out.println ("");
    System.out.println ("");

    System.out.println ("***** Testing getNFrom(...)...");
    System.out.println ("");

    System.out.println ("1 from Apple is just Apple...");
    System.out.println (oc.getNFrom("Apple", 1));
    System.out.println ("");

    System.out.println ("2 from Apple is Apple, Banana...");
    System.out.println (oc.getNFrom("Apple", 2));
    System.out.println ("");

    System.out.println ("3 from Grapefruit is Grapefruit, Orange, Pear...");
    System.out.println (oc.getNFrom("Grapefruit", 3));
    System.out.println ("");

    System.out.println ("3 from Pear (2nd to last) is Pear, Watermellon...");
    System.out.println (oc.getNFrom("Pear", 3));
    System.out.println ("");

    System.out.println ("2 from NonExistant is nothing...");
    System.out.println (oc.getNFrom("NonExistant", 2));
    System.out.println ("");

  }
}