Return to lecture notes index

15-100 Lecture 20 (Monday, March 3, 2008)

Loop Reinforcement

In reply to a question from a student, and in preparation for Thursday's exam, we did some reinforcement of loops: for, while, and do. Since this was just reinforcement, there are no notes here -- please refer to lecture 17.

Today's Challenge

Or goal today is to construct an OrderedArrayList. Basically, what we'd like to do is to make sure that, as we add things to our container, we add them in the right place to keep things in sorted order. For example, if we add names, we want them to be in alphabetical order. If we add other types of Comparable things, we want them to be in the order prescribed by use of compareTo().

This will result in traversals, such as toString(), appearing in order. And, it will enable searches, such as contains(), to become much faster. The cost will be, of course, a slower insert.

Comparable

Although we'll keep the basic structure of the Container, we now need to limit it to storing only Comparable Objects. The reason for this is that we need to esnure that anything that goes in can be placed into the OrderedContain in the proper order. This means being able to compare items pair-wise.

The basics of the OrderedArrayList are a quick adapatation of the old Container -- a quick search-and-replace, in effect:

class OrderedArrayList {

  private Comparable[] list;
  private int nextSlot;
  
  private static final int DEFAULT_SIZE = 10;
  private static final double GROWTH_FACTOR = 2.0;
  private static final String NL = System.getProperty ("line_separator");
  

  public OrderedArrayList() {
    list = new Comparable[DEFAULT_SIZE];
    nextSlot = 0;
  }
  
  
  public OrderedArrayList (int size) {
    list = new Comparable[size];
    nextSlot = 0;
  }
  

  public String toString() {
  
    String rep = "";
    
    for (int index=0; index < nextSlot; index++) {
      rep += items[index] + NL;
    }
  }

  private void grow() {

    Comparable[] biggerList =
                 new Comparable[(int)(GROWTH_FACTOR * list.length)];

    for (int index=0; index < nextSlot; index++)
      biggerList[index] = list[index];

    list = biggerList;
  }
}

Insert: A New Strategy

When it comes time to add an item into the container, we're going to adopt a different strategy. In the simple Container, we simply add()'ed the new item to the end. But, if we follow that strategy now, the container won't be ordered. And, sorting it will be a pain!

So, we're going to put the item into the right spot from the get-go. To do this, we first need to, as we did before, ensure that we've got enough space -- grow()'ing, if necessary.

Next, let's observe that in the past, we would have put the item into the nextSlot. In effect, we an view this nextSlot as a hole to be filled. At the end of the process, if the array is to accomodate one more item, regardless of that new item's eventual location, the nextSlot will need to be filled.

So, the name of the game for us is to start at the end, and ask the question, "Can this new item go into the nextSlot?" It can if, and only if, it is not less than nextSlot's predecessor. Otherwise placing it there would be placing it out of order.

If it can't go into the nextSlot, we know that we need to shift nextSlot's predecessor into nextSlot, in effect moving the hole one slot toward the front. Now, we repeat the process, bubbling the hole toward the front of the array until either (a) the new item is greater than this hole's predecessor, or the hole is at index 0.

If the new item is greater than the hole's predecessor we can drop it off into the hole. This is because anything after it got moved after it because it is greater. And, anything before it remains before it, because it is less than it. The hole is, in effect, in a position that is "just right".

Below is an example:

  OrderedArrayList: 2 4 6 8
  Number to insert: 3

  Moving the hole:

    2 4 6 8 _  //hole starts at back, compare 3 and 8 (need to move hole)
    2 4 6 _ 8  //compare 3 and 6 (need to move 6 back and hole forward)
    2 4 _ 6 8  //compare 3 and 4 (need to move hole)
    2 _ 4 6 8  //compare 3 and 2 (you have found the correct spot!)
    2 3 4 6 8  //insert 3 into the created hole and exit

If the hole works its way to index 0, it is because everything within the list is greater than the item, so it is safe to drop the item off into the 0th slot.

The solution looks like this:

  public void add (Comparable item) {

    // Nothing new here: Grow if needed
    if (nextSlot == list.length)
      grow();
 
    // Start the hole at the end and bubble toward the 0 index
    int hole;
    for (hole=nextSlot; hole > 0; hole--) {

      // Stop bubbling if the hole is in the right place
      if (list[hole-1].compareTo(item) < 0)
        break;

      // move the whole, if not. 
      list[hole] = list[hole-1];
    }

    // Drop the new item off into the hole
    list[hole] = item;
    nextSlot++;
  }

OrderedArrayList, so far

class OrderedArrayList {

  private Comparable[] list;
  private int nextSlot;
  
  private static final int DEFAULT_SIZE = 10;
  private static final double GROWTH_FACTOR = 2.0;
  private static final String NL = System.getProperty ("line_separator");
  

  public OrderedArrayList() {
    list = new Comparable[DEFAULT_SIZE];
    nextSlot = 0;
  }
  
  
  public OrderedArrayList (int size) {
    list = new Comparable[size];
    nextSlot = 0;
  }
  
  
  public void add (Comparable item) {
 
    if (nextSlot == list.length)
      grow();
  
    int hole;
    for (hole=nextSlot; hole > 0; hole--) {
      if (list[hole-1].compareTo(item) < 0)
        break;

      list[hole] = list[hole-1];
    }

    list[hole] = item;
    nextSlot++;
  }
  
  
  private void grow() {
  
    Comparable[] biggerList = 
                 new Comparable[(int)(GROWTH_FACTOR * list.length)];
    
    for (int index=0; index < nextSlot; index++) 
      biggerList[index] = list[index];
    
    list = biggerList;
  }

  
  public String toString() {
  
    String rep = "";
    
    for (int index=0; index < nextSlot; index++) {
      rep += items[index] + NL;
    }
  }

}