Lecture W1W1: Interfaces, Arrays, Linked Lists, and Amortization
August 26, 2026
Stuck after a refresher? Come to Student Hours (MW 10:15 - 11:15 AM, T/Th 11:15 AM - 12:15 PM) or Sam’s help hours (Sun 3:00 - 6:00 PM, Fri 3:00 - 4:30 PM at the QUAD).
Six problems, six kinds of background. Let’s put the notation for each back on the table.
| Problem | Background it exercises |
|---|---|
| 1 | Set notation and operations |
| 2 | Probability and expected value |
| 3 | Modular arithmetic |
| 4 | Proof by induction |
| 5 | Graph vocabulary + induction |
| 6 | Python and the word “subarray” |
If any of these felt brand new rather than rusty, tell me on HW0 by doing your honest best, and come see me or Sam this week.
By the end of this session, you will be able to:
On Monday we agreed on the rules of the game:
Today we use those rules to answer a new question: how should a program remember things?
Interface. A specification: which operations on stored data are supported, and what each one returns. Also called an API or an abstract data type.
Data structure. A representation: how the data is laid out in memory, with an algorithm for each supported operation.
Nearly everything we build this semester supports one of two contracts:
| Interface | Order is… | Signature question |
|---|---|---|
| Sequence | extrinsic: you put items at positions | “what is the \(i\)th item?” |
| Set | intrinsic: items carry keys | “do you hold an item with key \(k\)?” |
Today: Sequence. Next week: Set, via hashing.
Maintain an ordered collection \((x_0, x_1, \ldots, x_{n-1})\) of \(n\) items, with:
| Group | Operation | Meaning |
|---|---|---|
| Container | build(X) |
build a sequence from the items in iterable X |
len() |
return \(n\) | |
| Static | get_at(i), set_at(i, x) |
read or replace the \(i\)th item |
| Dynamic | insert_at(i, x), delete_at(i) |
add or remove at position \(i\) |
insert_first(x), delete_first() |
add or remove at the front | |
insert_last(x), delete_last() |
add or remove at the back |
The interface says nothing about memory. That is the data structure’s job.
A stack and a queue are just sequences that promise fewer operations:

Restricting an interface is powerful: the fewer operations you promise, the faster the implementation you can pick.
When a problem does not need an operation, do not pay for it.
An array of \(n\) items is \(n\) consecutive machine words, so finding item \(i\) is arithmetic, not searching:

get_at(i) and set_at(i, x) run in \(\Theta(1)\) worst-case time. This is the array’s superpower.



So every dynamic operation costs \(\Theta(n)\) in the worst case, even at the back, and even at the front.
A linked list stores each item in a node with two fields: node.item and node.next. The structure keeps one pointer, head, to the first node.

The price of this freedom: to reach item \(i\) you must walk the chain, so get_at(i) costs \(O(n)\).
A linked list is not a Python list. Python’s list is a dynamic array, which is coming up.
insert_first, one frame at a time


Two pointer writes, no shifting, no reallocation, and \(n\) never mattered: \(\Theta(1)\) worst case.
With your neighbor, fill in the worst-case cost, \(O(1)\) or \(O(n)\), of each cell:
| Operation | Array | Linked list |
|---|---|---|
get_at(i) / set_at(i, x) |
||
insert_first(x) / delete_first() |
||
insert_last(x) / delete_last() |
||
insert_at(i, x) / delete_at(i) |
Then answer: which workload makes the array win, and which makes the list win?
3 minutes.
| Operation, worst case | Array | Linked list |
|---|---|---|
build(X) |
\(O(n)\) | \(O(n)\) |
get_at(i), set_at(i, x) |
\(O(1)\) | \(O(n)\) |
insert_first(x), delete_first() |
\(O(n)\) | \(O(1)\) |
insert_last(x), delete_last() |
\(O(n)\) | \(O(n)\) |
insert_at(i, x), delete_at(i) |
\(O(n)\) | \(O(n)\) |
Each structure is excellent at exactly one thing. Can we get the best of both worlds?



Start empty and append \(n\) times with doubling. Resizes happen at sizes \(1, 2, 4, 8, \ldots\), so the total copying work is
\[1 + 2 + 4 + \cdots + 2^{\lfloor \log_2 n \rfloor} \;<\; 2n \;=\; \Theta(n).\]

Any sequence of \(n\) appends costs \(\Theta(n)\) total, even though single appends occasionally cost \(\Theta(n)\). The geometric series does the work: each resize doubles the distance to the next one.
An operation has amortized cost \(T(n)\) if any sequence of \(k\) operations costs at most \(k \cdot T(n)\) in total.
delete_last() alone is \(\Theta(1)\): decrement \(n\). But after many deletes the array is mostly empty, and we promised \(\Theta(n)\) space.list is a dynamic array: append and pop are amortized \(O(1)\).insert(0, x), pop(0), and del L[i] shift items: \(O(n)\). A loop that does pop(0) \(n\) times is \(\Theta(n^2)\).| Operation, worst case | Array | Linked list | Dynamic array |
|---|---|---|---|
build(X) |
\(O(n)\) | \(O(n)\) | \(O(n)\) |
get_at(i), set_at(i, x) |
\(O(1)\) | \(O(n)\) | \(O(1)\) |
insert_first(x), delete_first() |
\(O(n)\) | \(O(1)\) | \(O(n)\) |
insert_last(x), delete_last() |
\(O(n)\) | \(O(n)\) | \(O(1)\) amortized |
insert_at(i, x), delete_at(i) |
\(O(n)\) | \(O(n)\) | \(O(n)\) |
There is no free lunch, only informed trade-offs. Naming the workload first tells you which column to buy.
A Set maintains items with unique keys (item x has key x.key) and supports:
| Group | Operation | Meaning |
|---|---|---|
| Container | build(X), len() |
as before |
| Static | find(k) |
return the item with key \(k\) |
| Dynamic | insert(x), delete(k) |
add or remove by key |
| Order | find_min(), find_max(), find_next(k), find_prev(k) |
navigate by key order |
dict is one.find(k) seems doomed to \(O(n)\): check every item.Interfaces are problems; data structures are solutions. Arrays buy \(O(1)\) random access with rigid order, linked lists buy \(O(1)\) front edits with slow access, and dynamic arrays buy amortized \(O(1)\) appends by prepaying resizes. Choose by workload, and read the fine print on “amortized.”
Topics: Sorting (insertion sort, merge sort) and divide and conquer: recurrences and the Master Theorem. The sequence operations you priced today become the inner loops.
Supplemental reading (highly recommended): CLRS Chapter 2, in your own copy or online through Canvas/Perusall.
Upcoming deliverables:
