Feb 10, 2014 ... Review: java.util.ArrayList. ▻ A concrete implementation of the List interface/ADT
, using an array “under the hood”. ▻ It has two basic attributes ...
Review: java.util.ArrayList ArrayList ! data:! size: 4!
Class #07: Implementing the ArrayList ADT Software Design III (CS 340): M. Allen, 10 Feb. 16
!
A concrete implementation of the List interface/ADT, using an array “under the hood”
!
It has two basic attributes: ! !
Capacity: size of the internal array it uses (hidden from user) Size: the number of elements currently in the list (visible)
Wednesday, 10 Feb. 2016"
Review: Using ArrayList !
!
java.lang.Iterable ! !
java.util.Iterator ! !
! !
System.out.println( teams.contains( "Packers" ) ); Iterator iter = teams.iterator(); while ( iter.hasNext() ) {! System.out.println( iter.next() );! } !
!
java.util.Collection ! !
!
for ( String t: teams ) {! System.out.println( t );! }! Software Design III (CS 340)"
java.util.ListIterator ! !
Iteratorstyle looping java.util.List ! !
String old = teams.set( 0, "Eagles" );! System.out.println( "\nUsed to contain: " + old ); System.out.println( "Now: " + teams.get( 0 ) + "\n" );!
Wednesday, 10 Feb. 2016"
2"
Implementing the Full ArrayList Class
ArrayList teams = new ArrayList(); teams.add( "Steelers" ); teams.add( "Giants" ); teams.add( "Packers" );
Software Design III (CS 340)"
! !
Iterablestyle looping 3"
java.util.ArrayList ! ! Wednesday, 10 Feb. 2016"
A complex set of interfaces to implement, with many methods We will focus on a smaller subset, as given by MyArrayList class (text, pages 68–75) Software Design III (CS 340)"
4"
1
Elementary List Methods
Finding Things in an ArrayList Fixed amount of work for each method, independent of the size of the list/array.
// private instance variable! private int theSize = 0;!
public boolean isEmpty() { return theSize == 0; }!
public boolean contains( Object element ) ! {! for (int i = 0; i < size(); i++)! if ( theItems[i].equals( element ) ) return true; !
public T get( int idx ) {! if( idx < 0 || idx >= theSize ) ! throw new IndexOutOfBoundsException();!
}!
public int size() { return theSize; } !
This is therefore O(1) work: no important difference between 1 operation, 2 operations, 3 operations, etc.
return theItems[idx];! }! public T set( int idx, T newVal ) {! if( idx < 0 || idx >= theSize )! throw new IndexOutOfBoundsException();! T old = theItems[idx];! theItems[idx] = newVal;! return old; ! }! Wednesday, 10 Feb. 2016"
So long as the amount of work is fixed to some constant value, list size will eventually grow much larger than that, and is not an important factor in run-time of these methods.
Software Design III (CS 340)"
We rely on equals() method from the Object class. Important: we generally do not ! want to trust identity operator (==) to do this.
return false;!
public int indexOf( Object element ) ! {! for (int i = 0; i < size(); i++)! if ( theItems[i].equals( element ) ) return i; ! return -1;! }!
5"
Wednesday, 10 Feb. 2016"
The ensureCapacity() Method
Worst-case: O(n) work. Must loop over all elements of the inner array sometimes. This means that as array gets ! larger, method takes longer. Linear growth, so not too bad, but must still be taken into account on large data.
Software Design III (CS 340)"
Adding/Removing Items public void add( int idx, T x ) {!
@SuppressWarnings("unchecked") ! private void ensureCapacity( int newCap ) ! {! if( newCap < theSize ) ! return; ! T[] old = theItems; ! theItems = (T[]) new Object[newCap];! for ( int i = 0; i < theSize; i++ )! theItems[i] = old[i]; ! } !
for( int i = theSize; i > idx; i-- )! theItems[i] = theItems[i - 1];! theItems[idx] = x;! theSize++;! }!
Cannot instantiate generic arrays in Java.
O(n) complexity (where n is size of original array of objects) Wednesday, 10 Feb. 2016"
if( theItems.length == theSize ) ensureCapacity( size() * 2 + 1 );!
Ignore the method call (and save time) when new capacity is already smaller than current size
public T remove( int idx ) {!
Software Design III (CS 340)"
theSize--;! return removedItem;! }!
7"
!
If the list is full, we double its capacity.
When we add/remove an item, must make sure to shift over all remaining elements, to make room, and so there are no gaps in the array of objects.
T removedItem = theItems[idx];! for( int i = idx; i < size() - 1; i++ )! theItems[i] = theItems[i + 1];!
Must create an Object array and cast (this is why we suppress the warnings).
Must copy items over from original array to new larger one.
6"
Wednesday, 10 Feb. 2016"
Worst case: idx == 0 (item at start of list) O(n) complexity, due to all the necessary shifting.
Software Design III (CS 340)"
8"
2
Removing from the Rear of an ArrayList public T remove( int idx ) {!
Adding/Removing Inside ArrayLists !
T removedItem = theItems[idx];! for( int i = idx; i < size() - 1; i++ )! theItems[i] = theItems[i + 1];!
ArrayList is slowest when we add or remove object in the interior (any index 0 ≤ i ≤ size() – 2) !
theSize--;!
Shifting of elements up or down in data array takes an unavoidable O(n) amount of work, where n is size() of list
return removedItem;! }! !
!
To add to the rear, things are more complicated
A remove at end of list, idx == size() – 1, does very little
!
for-loop never runs (no shift needed)! theSize goes down, but no need to actually delete anything. return last active element of array.
!
1. 2. 3.
This the best case scenario: we can remove from end of list in constant O(1) time, and it doesn’t matter how long it is.
!
Wednesday, 10 Feb. 2016"
9"
Software Design III (CS 340)"
Adding to the End of an ArrayList !
!
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
10"
Adding to the End of an ArrayList
By doubling size when more room needed, we ensure that for N items total, we only re-size O(log2 N – 1) times at most, and don’t take too much memory at once The exact complexity analysis is a little more complicated, but it is possible to show that the cost of adding to the end of the list averages out to O(1) per object once we have reasonably large values of n !
When there is enough room in the array, this simply a fast array insert and increment of theSize, in constant O(1) time However, when the array is full, and we need to enlarge it using the ensureCapacity() method, this involves creating a new array, and then doing a full O(n) copy of original data
This is amortized analysis: we can show that, if the slowest operations don’t occur too often, then an occasional heavy cost is not so bad, from an overall perspective
!
By doubling size of array when re-sizing, we ensure that the cost of adding to the rear of the list averages out to O(1)
!
Important: this requires that when we resize the array, we multiply the size by some constant c > 1 !
!
If we did some fixed increase (e.g., capacity + 100), this wouldn’t work, and we would be back to O(n)
This multiplier does not have to be 2, exactly !
Java actually uses c == 3/2 for this multiplier
Java 6!
int newCapacity = oldCapacity * 3 / 2 + 1;!
Java 7+! int newCapacity = oldCapacity + ( oldCapacity >> 1 );! Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
11"
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
12"
3
ArrayList Complexity
The ArrayList Iterator
Method! T get( int i )!
O(1)!
int size()!
O(1)!
T set( int i, T element )!
O(1)!
boolean add( T element )!
O(1)! [amortized]!
}!
void add( int i, T element )!
O(n)!
T remove( int i )!
O(n)!
1.
int indexOf( T element )!
O(n)!
2.
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
Implementing the Iterator ArrayListIterator implements java.util.Iterator ! {! private int current = 0;! private boolean okToRemove = false;! public boolean hasNext() {! return current < size( );! }! public T next() { if ( !hasNext() ) throw new java.util.NoSuchElementException(); T item = theItems[current]; current++ ; okToRemove = true; }!
public class MyArrayList implements Iterable! {! public Iterator iterator()! {! return new ArrayListIterator(); ! }!
Time Complexity!
Class implements the Iterator interface, meaning that it must have methods hasNext(), next(), and remove().
Object uses own private variable to keep track of current position and tell if there are any more items to iterate over.
return item;
public void remove() {! if( !okToRemove )! throw new IllegalStateException( "…" );! current-- ; MyArrayList.this.remove( current ); okToRemove = false; }!
ArrayListIterator class is a private inner class
!
13"
If we try to run next() when there are no more elements left, we get an exception.
private class ArrayListIterator implements java.util.Iterator ! {! public boolean hasNext() {…}! public T next() {…} ! public void remove() {…}! }!
Written inside the list class itself, and private to it (can only be referenced directly inside the list code). Part of list class itself, so it can access other private elements directly, using things like theItems array.
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
14"
Implementing the Iterator public T next() {! Boolean flag: ensures if( !hasNext() )! can only be throw new java.util.NoSuchElementException(); remove() ! T item = theItems[current]; current++ ; okToRemove = true; return item; }!
called once after any time we call next().
(This behavior is part of full specification for Iterator interface.)
public void remove() {! if( !okToRemove )! throw new IllegalStateException();! current-- ;! MyArrayList.this.remove( current );! okToRemove = false;! }!
Over-riding: since iterator has its own remove() method, needs to use the Superclass.this notation to access the version that comes from its parent list-class.
}!
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
15"
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
16"
4
This Week !
Topic: Linear Structures
!
Read: Text, chapter 03
!
In Lab: Friday, 12 Feb.
!
Homework 01: due Today, 10 Feb. (5:00 PM)
!
Office Hours: Wing 210 ! !
Tuesday & Thursday: 10:00–11:30 AM Tuesday & Thursday: 4:00–5:30 PM
Wednesday, 10 Feb. 2016"
Software Design III (CS 340)"
17"
5