Introduction 
This lecture covers the details of how ordered collection classes are
defined, implemented, and used.
Little of this material is new: we have already introduced stacks and queues in
a previous lecture (including their implementations by the SimpleStack
and SimpleQueue classes), and priorities queues in Programming
Assignment 4 (the SimplePriorityQueue class).
Unlike all the other collections that we will study, these are NOT in the standard Java library. So instead, I have written my own descriptions for these classes (in the edu.cmu.cs.pattis.orderedCollections package) in a style similar to the collections that we will study in the standard Java library. These descriptions unify all these data types under the OrderedCollections interface, bringing uniformity to the names of the methods: push and enqueue become add; pop and dequeue become remove. We cover these collections first because they are familiar and a bit simpler to understand than lists, sets, and maps (which are covered in subsequent lectures). You can download, unzip, run, and examine all this code (along with a driver program) in the Ordered Collections Demonstration. 
Design of OrderedCollection Classes  In this section we will examine in detail the collection classes that implement the OrderedCollection interface. We will examine the overall relationships among this interface, the abstract classes that implement it, and the concrete classes that extend these abstract classes; these features naturally arrange themselves into three vertical levels in a hierarchy. The following legend explains the three levels and some of the notation used. 
For ordered collections, we will explore the following hierarchy of interfaces, abstract classes, and concrete classes. 
This interface is implemented by abstract classes (two levels, which supply
some but not all of the needed methods) which are extended by concrete
classes that inherit some behvaior from the abstract classes and concretely
define all their abstract methods.
Recall that concrete subclasses automatically implement the interfaces that
their superclasses implement, and [abstract]classes can implement more
than one interface (but can extend only one superclass); this is a
fundamental difference between interfaces and classes.
In the next three sections, we will examine the Javadoc of this interface, the abstract classes that implement it, and the concrete classes that extend these abstract classes (the ones using arrays, not linked lists yet). 
Interfaces  The methods specified in the OrderedCollection interface are summarized in the following Javadoc (you can read the full Javadoc online, using the Javadoc of Course API link). The semantics of most methods should be somewhat intuitive. Primarily, objects can be added and removed from an ordered collection: their order of removal is based on the type of ordered collection: LIFO (for stacks), FIFO (for queues), and "priority ordering" for priority queues. 
Fundamentally, the add method adds an object to the ordered collection
(generalizing push and enqueue).
Note that add returns true if its value is added to the
collection (another way to say this is the size increases): for ordered
collections this is always the case, but with a collection like set, which
has no duplicate values, it will return false if the element is
already stored in the set.
The addAll method iterates through every object in its parameter
ordered collection, and adds each (in order) to this collection.
The remove and peek methods return a reference to the next object in the ordered collection (according to its behavior) respectively removing or not removing it; these methods work only if isEmpty returns true (i.e., size returns 0). Note that remove returns true if it removes a value from the collection (another way to say this is the size decreases): for ordered collections this is always the case, but with a collection like set, specifying to remove a value might return false if that value is not in the set. The size method returns the number of elements in the ordered collection, and the clear method empties the ordered collection (its size becomes 0). The iterator method returns an iterator whose next method iterates over the ordered collection in the order the elements would be removed. Finally, there are various methods that return this ordered collection as an array or Collection (this interface is to be covered in the next lecture). Now we will examine an abstract class and abstract subclass that implement a large number of these methods, leaving the concrete subclass to implement/override just a few (mostly add, remove, peek, and especially iterator, which many other methods use). Remember that there are 13 methods specified in this interface. 
Abstract Classes  Now we will examine the Javadoc of an abstract class and its abstract subclass that mostly implement the interface specified above (although some of its methods are abstract). The OrderedCollection interface specified 13 methods. The AbstractOrderedCollection class specifies one protected constructor and 13 methods; it doesn't define equals which is inherited from the Object class that this one implicitly extends (and overridden is the abstract subclass in the next section); it adds the specification of a toString method. Of these 13 (=131+1) methods, all but the iterator and peek are defined here, although operations like add and remove are only partially implemented, and must be overridden. Here is the Javadoc of AbstractOrderedCollection. 
Basically, this class stores as instance variables the int values
objectCount (incremented, decrements, and checked by
add, remove, and size) and modCount
(checked by failfast iterators).
Read the .java file for this class and note how all it methods are
implemented.
For example addAll can be implemented by the code
public boolean addAll (OrderedCollection o) { modCount++; boolean modified = false; Iterator e = o.iterator(); while (e.hasNext()) if(add(e.next())) modified = true; return modified; }even though the iterator method is abstract and the add method will be overridden. Given that these methods are promised (in the case of add, exists but is not complete), this code make sense to Java here: the ordered collection o is iterated over, and each of its elements is added to the this ordered collection. We could also write this loop as while (e.hasNext()) modified = add(e.next())  modified;but NOT as while (e.hasNext()) modified = modified  add(e.next();because the shortcircuit evaluation would not execute any more calls to add once modified was set to true. Likewise, the clear method can be implemented by the code public void clear () { if (!isEmpty()) modCount++; while (!isEmpty()) remove(); } which removes values (ignoring the returned references) until the ordered collection is empty. Finally, all the to... methods (toArray, toCollection, and toString) can be implemented, again using the iterator method, which is promised to be defined in the concrete subclass. For example public Object[] toArray() { Object[] result = new Object[size()]; Iterator e = iterator(); for (int i=0; e.hasNext(); i++) //or... int i=0; i<result.length; i++ result[i] = e.next(); return result; }where an array of the right size is allocated, and this ordered collection is iterated over, and each of its elements is put into its correct array position. The AbstractStack, AbstractQueue, and AbstractPriorityQueue, classes all extend AbstractOrderedCollection. Each also specifies one protected constructor, and specifies just one method: it overrides the equals method inherited from Object. This method allows only stacks to be equal to other stacks, and only then if their elements, ordered LIFO, are all equal. Here is the Javadoc of AbstractStack, which is very short; AbstractQueue, and AbstractPriorityQueue are defined similarly. 
Look the Methods inherited from class java.lang.Object.
Is it a bug in Javadoc that since this class overrides equals the
first comma has nothing in front of it?
The equals method in this class is defined as follows: public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof AbstractStack)) return false; if ( size() != ((AbstractStack) o).size() ) return false; Iterator e1 = iterator(); Iterator e2 = ((AbstractStack) o).iterator(); while(e1.hasNext() && e2.hasNext()) { //simplify to just e1.hasNext()? Object o1 = e1.next(); //...stacks have the same size! Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return true; }All equals methods look similar to this one. First, if the two objects being compared are the same, it returns true. Second, if the parameter isn't an AbstractStack (it can be any concrete extension of this abstract class) it returns false. Third, if the sizes of the stacks are unequal, it returns false. Now comes the interesting part, both stacks (which are now known to have the same size, so the test can be simplified) are traversed in a loop, and their elements are checked for equality (null is a special case): if any are unequal, it returns false; if all are equal, it eventually terminates the loop and returns true. My declaration of objectCount and use of this instance variable in add and remove can be criticized; critics would prefer this protected instance variable to be removed from this class and instead defined private in the subclasses; and, these methods to be declared abstract here and defined in the subclass, rather than be declared concrete here and overridden in the subclass. Next we will examine the Javadoc and implementation a concrete class that extends AbstractStack and one that extends AbstractPriorityQueue. 
Concrete Classes  Now we will examine the Javadoc of a concrete class that extends AbstractStack and one that extends AbstractPriorityQueue. The ArrayStack class is implemented with an array backing the stack (we will examine the other implementation, LinkedStack, in detail after we discuss linked lists). The ArrayStack class defines 5 public constructors and 7 methods: it overrides the inherited methods add, remove, and toString; it concretely defines two inherited abstract methods, iterator and peek; and it defines two new methods, not mentioned previously: ensureCapacity and trimToSize, which relate only to array implementations of stack (not to stacks theselves). Here is the Javadoc of ArrayStack (because of size constraints, it appears in a smaller font). 
Note that we can construct an empty stack (with some small backing array),
an empty stack with a backing array whose length starts at some initial
capacity, and a nonempty stack with values added from a Collection
(studied in the next lecture), object array, or any
OrderedCollection (if they are not empty).
We can call EnsureCapacity to increase the length of the backing array
to any value, or trimToLength to decrease it to the mininmum
length needed to store all its current values.
The other methods here just do what they are supposed to, for stacks, following LIFO behavior. Now on to the ArrayPriorityQueue class. It is implemented with an array backing the priority queue. The ArrayPriorityQueue class defines 5 public constructors and 7 methods: it overrides the inherited methods add, remove, and toString; it concretely defines two inherited abstract methods, iterator and peek; and it defines two new methods, not mentioned previously: ensureCapacity and trimToSize, which relate only to array implementations of priority queues (not to priority queues theselves). Here is the Javadoc of ArrayPriorityQueue (because of size constraints, it appears in a smaller font). 
As with stack constructurs, we can construct an empty priority queue (with
some small backing array), an empty priority queue with a backing array
whose length starts at some initial capacity, and a nonempty priority queue
with values added from a Collection (studied in the next lecture),
object array, or any OrderedCollection.
We can call EnsureCapacity to increase the length of the backing array
to any value, or trimToLength, which decreases it to the mininmum
length needed to store its current values.
In addition, note that each constructor for a priority queue requires a parameter that is a reference to an object that is constructed from a class implementing the Comparator interface (a mouthful, but the same mouthful every time). This is the object that determines the relative priorities of any two elements in the priority queue; with this object we can arrange to keep the backing array sorted from lowest to highest priority. The Javadoc details specify that its matching argument must be nonnull, otherwise the constructor throws an exception. So, the structure leading from the OrderedCollection interface to the ArrayStack, ArrayQueue, and ArrayPriorityQueue concrete classes involve all sorts of interesting inheritance of abstract and concrete methods. Again, we can USE all these classes without knowing this information, mostly by examining just the OrderedCollection interface and the constuctors for these classes, and knowing that they implement their methods efficiently. For this last aspect, skip a section to see a discussion of the performance of methods in terms of big O notation, where n is typically the number of elements stored in the collection. 
Iterators for OrderedCollection 
Unlike other collections, the main purpose of ordered collection is just
to remove values is an interesting order: LIFO, FIFO, or priority order.
Thus, the iterators for these classes all throw
UnsupportedOperationException when remove is called.
This simplifies (by just a bit) their implementation, and doesn't impact
their use much (so, we will live with this simplification and restriction).
Note that iterators are used frequently in the implementation of many methods itself, even in the abstract classes. 
Complexity Classes 
The following table summarizes the complexity classes of all the methods
in the different implementations of OrderedCollection.
When we learn about heaps (technically a tree, but a special kind that
can be backed by an array), we will see another implementation of priority
queues with interesting complexity classes for add and remove.
In the table below * means amortized complexity. That is, when we add a value in an array, most of the time we perform some constant number of operations, independent of the size of the array. But every so often, we must construct a new array object with double the length, and then copy all the array's elements into it. If we pretended that each add did more operations (but still a constant number), that number would dominate the actual number of operations needed for all the doubling. In the table below ** means that the parameter to the method is some collection (or array) storing M elements. 
Method  ArrayStack  LinkedStack  ArrayQueue  LinkedQueue  ArrayP...Q...  ArrayUnsortedP...Q... 

add  O(1)*  O(1)  O(1)*  O(1)  O(N)  O(1)* 
addAll  O(M)* **  O(M)**  O(M)* **  O(M)**  O(MN)**  O(M)* ** 
clear  O(N)  O(1)  O(N)  O(1)  O(N)  O(N) 
remove  O(1)  O(1)  O(1)  O(1)  O(1)  O(N) 
peek  O(1)  O(1)  O(1)  O(1)  O(1)  O(N) 
size  O(1)  O(1)  O(1)  O(1)  O(1)  O(1) 
isEmpty  O(1)  O(1)  O(1)  O(1)  O(1)  O(1) 
equals  O(N)  O(N)  O(N)  O(N)  O(N)  O(N log_{2}N) 
iteration...  O(N)  O(N)  O(N)  O(N)  O(N)  O(N log_{2}N) 
toString  O(N)  O(N)  O(N)  O(N)  O(N)  O(N log_{2}N) 
toArray  O(N)  O(N)  O(N)  O(N)  O(N)  O(N log_{2}N) 
toCollection  O(N)  O(N)  O(N)  O(N)  O(N)  O(N log_{2}N) 
Using backing arrays, and length doubling, the array length for storing N elements is never more than 2N words of memory; using linked lists, storing N elements always requires 2N words of memory. 
Simple Examples of Using Ordered Collection Class 
In this section we will illustrate a few interesting uses of ordered
collection classes.
There are many many (many) more.
First, we will use a stack to reverse an array. Assume that we have declared Object[] o; and stored into it a reference to an object filled with values that we want to reverse. AbstractStack s = new ArrayStack(); for (int i=0; i<o.length; i++) //Push all values on stack s.add(o[i]); for (int i=0; i<o.length; i++) //Pop them off in "reverse" order o[i] = s.remove();Technically we can declare s with the OrderedCollection interface, but we use AbstractStack to make our intent clearer; certainly we want only subclasses of AbstractStack (not, for instance, ArrayQueue) to be allowed. Second, we can use the same code, with a different class (priority queue), to get a much different result: sorting. Again, assume that we have declared Object[] o; and stored into it a reference to an object filled with values that we want to sort; also assume that c stores a reference to the Comparator that we want to use. AbstractPriorityQueue pq = new ArrayPriorityQueue(c); for (int i=0; i<o.length; i++) pq.add(o[i]); for (int i=0; i<o.length; i++) o[i] = pq.remove();Performing N enqueues (an O(N) operation) is O(N^{2}). Performing N dequeues (an O(1) operation) is O(N). Doing one, then the other, is O(N^{2}) + O(N) = O(N^{2}), so this is much worse that calling Arrays.sort(o,c), which is O(N Log_{2} N), Third, in a "perfect" HTML document, each "opening" tag has a matching "closing" tag, nested the right way: <b><pre>some sentence</pre></b> is correct but <b><pre>some sentence</b></pre> is not: this is similar to matching different kinds of parentheses: [()] is legal but [(]) is not. Assume that docIterator is an iterator for tags in an HTML document. Calling next() returns a String with the next tag: e.g., b or /b; pre or /pre. We can use a stack to check whether an HTML document is perfect with the following code; it finishes or throws IllegalStateException whenever a mismatch is found. Note that each opening tag is pushed on the stack; each closing tag is attempted to be matched against the top of the stack. AbstractStack s = new ArrayStack(); while ( docIterator.hasNext() ) { String tag = (String)doc.next(); if ( tag.charAt(0) != '/' ) //Test tag: closing or opening s.add(tag); else if ( s.isEmpty()  !tag.substring(1).equals(s.peek()) ) throw new IllegalStateException("Tag mismatch"); else s.remove(); } if (!is.isEmpty()) //Tags left unmatched throw new IllegalStateException("Closing tag(s) missing");Fourth, we can use a stack to compute the area of a 2d figure quickly, not by scanning all it internal cells, but by traveling around its boundary (analogous to Green's Theorem in analysis). Look at the following picture

To compute the area of this figure, we could examine all 696 (24 x 29) cells,
counting the ones that are purple.
Another approach, which works for all convex pictures, is to start at the top
leftmost purple cell (in the picture above, it is labeled by 1) and
iterate over all the remaining boundary cells in a clockwise order
(labeled by 253).
Each time that we move farther right (X increases), we push the current Y
coordinate of the cell on to a stack; each time that we move to the left,
we pop the top of the stack and subtract it from the current Y coordinate
(and add 1): this is a count of the cells (vertically) between the top and
bottom coordinate.
After we have iterated over all the cells (returned to the starting point), we
have computed the area of the figure by circumnavigating its boundary.
Assume that figureIterator is an iterator for walking the boundary of a figure: in the example above it first returns the point (1,2), then (2,7), then (3,6), then (4,6), etc. (so far, pushing each of these on the stack). The first time it doesn't move to the right (label 27), it computes the vertical area as 3 (1311+1), then adds 4 (1411+1), then adds 6 (149+1), etc. (now subtracting from the current Y coordinate the Y coordinate of the point popped off the stack). Each pushed value (at the top of the figure) is popped off exactly when the the corresponding point at the bottom of the figure is being processed, allowing us to account for all the cells in the vertical strip between them (inclusive). We can use a stack to compute the area with the following code. AbstractStack s = new ArrayStack(); int sum = 0; Point prev = new Point(1,1); //To the left of any point! while ( figureIterator.hasNext() ) { Point curr = (Point)figureIterator.next(); if (curr.x > prev.x) s.add(curr); else sum += curr.y  ((Point)s.remove()).y + 1; prev = curr; }This process can be run quickly, because it examines only cells on the boundary (which is O(N)), not all the internal cells, (which is O(N^{2}). Finally we can simulate a supermarket using queues (for the checkout lines) and priority queues (for the scheduling events; the event to happen most closely in the future has the highest priority). A simulated supermarket is specified by an array storing the maximum number of items that can be checkedout in each line. The events are "enter the store and start shopping" (at random intervals), "enter a checkout line" (based on the number of items bought, the sizes of the lines, and how many items are allowable), start checkout process (keep track of shopper's wait time: from entering a line to checking out), and "exit store". The unhappiness of a custom is computed (line wait time/shop time) and an average unhappiness over all shoppers is reported. The program also reports the running time and simulation speed (# of events processed/second). You can download, unzip, run, and examine all this code in the Supermarket Simulation. 
Problem Set 
To ensure that you understand all the material in this lecture, please solve
the the announced problems after you read the lecture.
If you get stumped on any problem, go back and read the relevant part of the lecture. If you still have questions, please get help from the Instructor, a CA, or any other student.
