Here is a quick sketch of the solutions. In grading, I am looking only for a few things on each question, and an overall understanding of the important concepts. VERSION A 1. [SCORING BY PARTS: 10; 10; 10; 20] a. The size of the list is changing everytime you remove, so only about one-quarter of the list would be removed b. remove from the front of an ArrayList is an O(N) operation. There are O(N) removes, so the total cost is O(N^2). c. remove from the front of a LinkedList is an O(1) operation. There are O(N) removes, so the total cost is O(N). d. For a quadratic algorithm, 2 times the input means 4 times the running time. But if Machine B is twice as fast as Machine A, instead of taking 4 times as long, it will take only 2 times as long. 2. [SCORING BY PARTS: 15 for toString; 10 for Big-Oh; 15 for addAfter; 10 for addLast] [Bad bounds in loop of toString -4 each; not using StringBuffer -5] [In addAfter theSize++ is 2 points] a. public String toString( ) // Runs in O(N) { StringBuffer result = new StringBuffer( "[ " ); for( Node p = beginMarker.next; p != endMarker; p = p.next ) result.append( p.data + " " ); result.append( "]" ); return result.toString( ); } b. private void addAfter( Node p, AnyType x ) { p.next = p.next.prev = new Node( x, p, p.next ); theSize++; } c. public void addLast( AnyType x ) { addAfter( endMarker.prev, x ); } 3. public static Map> groupWords( String [ ] arr ) { Map> result = new TreeMap>( ); for( String s : arr ) { List stringList = result.get( s.length( ) ); if( stringList == null ) { stringList = new ArrayList( ); result.put( s.length( ), stringList ); } stringList.add( s ); } return result; } 4. public Set expandAlias( Map> addressBook, String alias ) { Set result = new TreeSet( ); if( alias.indexOf( '@' ) >= 0 ) // Single email address result.add( alias ); else // No @, so must be alias { List expandsTo = addressBook.get( alias ); if( expandsTo != null ) for( String name : expandsTo ) result.addAll( expandAlias( addressBook, name ) ); } return result; }