**Stacks and queues**. Understand the semantics of each.

**Linked lists**.
Understand how they can be used to implement a stack or a queue, how to calculate the memory used by a linked list (using the 64-bit memory
model) for N items in a queue, and how to show that queue and stack operations complete in constant time.

**Resizing arrays**.
Understand how they can be used to implement a stack or a queue.
Understand why the worst case memory usage and running times are different than the best case.

**Amortized analysis**.
The idea is simpler that it might seem at first. If we say that X-operations take amortized f(M) Y-operations, this means that if we start with
an *empty data structure*, the average cost for any sequence of M X-operations is f(M) Y-operations.

For example, for a resizing array stack, we say that push and pop operations take amortized constant time. This means that if we start with an empty stack, any sequence of pushes or pops take on average a constant number of array accesses per push or pop. In this example X is { push, pop }, Y is array accesses, and f(M) is just 1.

**Generics**.
Understand that these provide the ability to parameterize data types. Understand why this approach is superior to other approaches (writing
separate classes, using the Object type and doing runtime casting).

**Compile time vs. run time errors**. Understand why the former are preferred.

**Iterators**.
Understand what it means for a class to implement the `Iterable` interface.
Understand what a class must do to implement the `java.util.Iterator` interface.
Understand how the foreach loop (enhanced for loop) works.
Understand how to convert code using a foreach loop into equivalent longhand code.

**Loitering**. Understand how to avoid loitering in Java.

- Textbook 1.3.6
- 1.3.3
- 1.3.22, then 1.3.23
- Understand why the we prevent loitering by adding the line A[N] = null in Algorithm 1.1 on page 141 of the book. Why do we not have a special purpose line like this for our linked list implementation (page 149, algorithm 1.2).

- Fall 2008 Midterm, #3b (you don't need to know what a symbol table is to do this problem) -- this is a great problem!
- Textbook 1.3.5
- Textbook 1.4.35 - a pushdown stack is just a stack.
- Textbook 1.4.36 [important note: they recommend using a static inner class to reduce Node overhead, hence the disagreement with the lecture slides!]
- Consider Algorithm 1.1 on page 141 of the book. We showed in lecture that the memory usage of this class is ~8N and ~32N bytes in the best and worst cases respectively. If we get rid of the line A[N] = null, which prevents loitering, how does this affect the best and worst case memory usage of our resizing array based stack? Highlight for answer: It doesn't! Follow up question with no provided answer: Then why do we care?

- Textbook 1.4.32
- Suppose we have a resizing array that increases in size by K entries when the array is
full, and decreases in size by K entries when the array has K empty entries. Show that the push and pop take amortized M time for some worst
case sequence. Give an example of a worst case sequence. Observe that this results in M
^{2}time for M operations.