Please send questions to st10@humboldt.edu .
/* Cs132ArrayList.java 1.0                                */
/* by Sharon Tuttle                                       */
/* last modified: 3-7-03                                  */
/*                                                        */
/* A concrete subclass of Cs132AbstractList,              */
/* using an array-based implementation                    */

public class Cs132ArrayList extends Cs132AbstractList
{
    /*------------------------------------
     fields
    -------------------------------------*/

    // array containing list data
    private Object data[];

    // number of items currently in list
    private int count;
    
    // amount to "increment" array, when necessary
    static final int INCR_AMT = 10;
    
    /*--------------------------------------
     constructors
    ---------------------------------------*/

    // creates an empty list
    public Cs132ArrayList()
    {
        this.data = new Object[INCR_AMT];
        this.count = 0;
    }
    
    /*-------------------------------------------------------
     accessors
    -------------------------------------------------------*/ 

/*    public Cs132ListNode getData()
    {
        return this.data;
    }
*/   
    /*-------------------------------------------------------
     modifiers
    -------------------------------------------------------*/ 
/*    public void setHead(Cs132ListNode newHead)
    {
        this.head = newHead;
    }
*/
    /*------------------------------------------
     overridden methods
    -------------------------------------------*/
    public String toString()
    {
        String elementString = "";
        
        for(int i = 0; i < this.size(); i++)
        {
            elementString = elementString + this.data[i] + "\n";
        }
        
        return "Cs132ArrayList[size = " + this.count + ", elements are:\n"
               + elementString
               + "]";
    }

    /*---------------------------------------
     other methods
    ----------------------------------------*/
    
    /*-----------------------------------------------------------
     isEmpty()
     Purpose: return true if this list contains no elements, return
              false otherwise.
     Hey --- why don't I just inherit this from Cs132AbstractList?
    -----------------------------------------------------------------*/
    
    /*--------------------------------------------------------
     size
     Purpose: return current size of the list
     
     (why not make this an accessor? Well, I'd like to hide
     the implementation detail count --- but, whether I
     store it or not, finding the size of a list is a useful
     piece of info for many lists.)
    ----------------------------------------------------------*/
    public int size()
    {
        return this.count;
    }

    /*--------------------------------------------------------
     expandArrayWhileAdd
     Purpose: increase the size of the array when the number
              of elements justifies it (that is, when an
              addition to the list threatens to overflow it).
              (a private, local operation, of course)
    -----------------------------------------------------------*/
    private void expandArrayWhileAdd(int newElemPos, Object newElement)
    {
        Object[] newArray = new Object[this.data.length + INCR_AMT];
        
        // copy the elements from the current array to the new,
        // bigger array; loop goes 1 time more than usual
        // because of the new element being added along the way
        int newI = 0;
        for (int oldI=0; oldI < this.size()+1; oldI++)
        {
            // is this where new element is supposed to go?
            if (oldI == newElemPos)
            {    
                newArray[newI] = newElement;
                newI++;   // need extra incrementation this time only...
            }
            // if new element not at END of array...
            if (oldI != this.size())
            {
                newArray[newI] = this.data[oldI];
                newI++;
            }
        }
        
        // now, THIS should be our new data array
        this.data = newArray;
        this.count = this.count + 1;
    }
    
    /*-------------------------------------------------------
     addFirst
     Purpose: add given data newObj to beginning
              of list.
     Hey --- why don't I just inherit that from Cs132AbstractList?
    ---------------------------------------------------------*/

    /*-------------------------------------------------------
     addLast()
     Purpose: add given data newObj to end
              of list.
     Hey --- why don't I just inherit this from Cs132AbstractList, 
     too? Because I can directly implement it more efficiently;
    ---------------------------------------------------------*/
    public void addLast(Object newElement)
    {
        // will adding the element overflow the array? If so,
        // add it in as array is copied into a larger array...
        if (this.data.length == this.size())
        {
            this.expandArrayWhileAdd(this.size(), newElement);
        }
        
        // else, we add it in the current array here...
        else
        {
            this.data[this.size()] = newElement;
            this.count = this.count + 1;
        }
    }

    /*----------------------------------------------------------------
     add()
     Purpose: add given data newElement to list at position index (where
              0 is the index of the first item in the list, 1 is the
              index of the 2nd item in the list, etc.)
              Throw a ListIndexOutOfBoundsException if the list
              index is not between 0 and the size of the array
              (I *could* add a new element to the end --- thus "size"
              instead of the usual "size - 1").
              BUT note --- those elements "after" this position ARE
              shifted "up" a position!
    -----------------------------------------------------------------*/
    public void add(int index, Object newElement) throws 
        ListIndexOutOfBoundsException
    {
        // complain if trying to add an element to an illegal position
        if ((index < 0) || (index > this.size()))
        {
            throw new ListIndexOutOfBoundsException(index);
        }
        
        // if get here, index is reasonable.
        
        // will adding the element overflow the array? If so,
        // add it in as array is copied into a larger array...
        if (this.data.length == this.size())
        {
            this.expandArrayWhileAdd(index, newElement);
        }
        
        // else, we add it in the current array here...
        else
        {
            // shift down everything from position index to the end
            for (int i = this.size(); i > index; i--)
            {
                this.data[i] = this.data[i-1];
            }
 
            // ...and should be able to add new item now
            this.data[index] = newElement;
            this.count = this.count+1;
        }
    }

    /*----------------------------------------------------------------
     getFirst()
     Purpose: IF list is not empty, return FIRST element in list.
              (this is its VALUE, not the node itself!)
              If it IS empty, throw a ListEmptyException
     Let's inherit this from Cs132AbstractList...
    -----------------------------------------------------------------*/
    
    /*----------------------------------------------------------------
     getLast()
     Purpose: IF the list is not empty, return the LAST element in list.
              (this is its VALUE, not the node itself!)
              If it IS empty, throw a ListEmptyException
     Let's inherit this, too.
    ----------------------------------------------------------------------*/

    /*----------------------------------------------------------------
     get()
     Purpose: return the element at position index in the list
              (where 0 is the index of the first item in the list).
              If the list is empty, throw a ListEmptyException.
              If the index is not between 0 and (list's size - 1),
              throw a ListIndexOutOfBoundsException.
    ---------------------------------------------------------------------*/
    public Object get(int index) throws ListEmptyException,
        ListIndexOutOfBoundsException
    {
        // is list empty?
        if (this.size() == 0)
        {
            throw new ListEmptyException();
        }
        
        // list is NOT empty, so now
        // make sure that index is reasonable --- if not, complain
        if ((index < 0) || (index >= this.count)) 
        {
            throw new ListIndexOutOfBoundsException(index);
        }

        // index must be reasonable, if reach here ---
        // grab that list element  
        return this.data[index];
    }   
    
    /*----------------------------------------------------------------
     remove()
     Purpose: This seeks to remove the element at position index
              of the list (where 0 is the index of
              the first element in the list). It will do so and return
              the object removed if the index is indeed a position
              in the list. (elements "above" in this list are now
              one position "lower")
    
              If the list is empty, however, it will
              throw a ListEmptyException, and if the index is not
              a position in the list, it will throw a 
              ListIndexOutOfBoundsException.
    --------------------------------------------------------------------*/
    public Object remove(int index) throws ListEmptyException,
        ListIndexOutOfBoundsException
    {
        // is list empty?
        if (this.size() == 0)
        {
            throw new ListEmptyException();
        }
        
        // list is NOT empty, so now
        // make sure that index is reasonable --- if not, complain
        if ((index < 0) || (index >= this.count)) 
        {
            throw new ListIndexOutOfBoundsException(index);
        }

        // since it is reasonable, can remove it by shifting
        // all "above" it "down" one position, and resetting count
        Object deletedElement = this.data[index];
        for (int i=index; i < this.size()-1 ; i++)
        {
            this.data[i] = this.data[i+1];
        }
        this.count = this.count-1;
        return deletedElement;
    }
    
    /*----------------------------------------------------------------
     clear()
     Purpose: empties the LinkedList instance that calls this.
    ----------------------------------------------------------------------*/
    public void clear()
    {
        this.count = 0;
    }
}