Stack Operations
A stack is a sequence of items piled one on top of the other, and only the top item is accessible at any time.
Why Only the Top Item Matters
Many beginners picture a collection of items as something you can reach into at any position. A stack does not work that way. It is built around one rule: at any moment, only one item is directly available, and that is the item on top. A stack is a sequence of items piled one on top of the other, and only the top item is accessible at any time. Once you accept that single rule, most of the behavior of a stack follows from it.
What do you think happens?
If you have three items in a stack and want the bottom one, what must happen to the items above it?
Reveal answer
Every item above the bottom one must be removed first, because only the top item is directly available.
An item lower in the stack can only be removed after every item above it has been popped off. The bottom item is reachable only once the pile above it is gone.
Removal Order and the One-Way Doorway
The restriction to the top item creates a fixed ordering rule for removal. An item lower in the pile cannot be taken out until every item stacked above it has first been removed. A helpful picture is a one-way doorway: whatever entered most recently is the first thing that can leave. This is why a stack suits any task where the most recent piece of work must be handled before older pieces.
The rule is about position, not about content. The source notes that a stack can hold items of any type; its example uses int values. Whether the items are numbers, names, or other objects, the pile-like behavior is identical, because what matters is where each item sits, not what it contains.
The Three Core Operations
A stack is used through a small set of operations. Each one has a specific job.
- push adds a new item to the top of the stack.
- pop removes the top item and returns it to the caller.
isEmptyreports whether the stack currently has no items. It returns true when the stack holds nothing and false otherwise.
The source describes push and pop as operations that can be implemented as instance methods when the stored items are int values. Notice that pop does two things at once: it changes the stack by removing the top item, and it hands that item back. isEmpty does not change the stack at all; it only answers a question about it.
Tracing a Sequence of Operations
The best way to internalize the stack rule is to trace it. Follow a short sequence and, after each operation, write down the full contents of the stack and identify the item on top. Here the stack is written from bottom to top. Start with an empty stack and apply these operations in order: push 4, push 7, push 2, pop, pop.
Tracing push and pop on a stack of int values
Starting from an empty stack, apply push 4, push 7, push 2, pop, pop. State the contents of the stack after each step, and state what each pop returns.
- 1Step 1: push 4
The stack was empty, so 4 becomes the only item. Contents: [4]. Top: 4.
- 2Step 2: push 7
7 is added to the top, above 4. Contents: [4, 7]. Top: 7. The 4 is now buried, not removed.
- 3Step 3: push 2
2 is added to the top. Contents: [4, 7, 2]. Top: 2.
- 4Step 4: pop
The top item, 2, is removed and returned. Contents: [4, 7]. Top: 7. The pop returns 2.
- 5Step 5: pop
The new top item, 7, is removed and returned. Contents: [4]. Top: 4. The pop returns 7. Note that 7 left before 4 because it was pushed later.
After the five operations the stack holds [4], the pops returned 2 and then 7, and the item 4 can only leave once it is the top item.
What do you think happens?
In the same stack, after the two pops, what item is on top, and what would a third pop return?
Reveal answer
The top item is 4, and a third pop would return 4, leaving the stack empty.
After the two pops the stack is [4]. Popping it removes the last item and returns it, so the stack becomes empty.
Why Popping an Empty Stack Is an Error
The source is clear that popping from an empty stack is an error. There is no top item to remove and return, so a program that calls pop without checking has a bug. The purpose of isEmpty is to let code find out, before popping, whether there is anything to remove. Checking isEmpty before calling pop is the safe pattern.
2
7
False
4
True- push adds an item to the top of the stack.
- pop removes the top item and returns it.
isEmptyreturns True only when no items remain.- Each printed value is the result of the call on that line, in order.
nothing to pop- The stack is created empty, so
isEmptyreturns True. - The guard stops execution before pop is called, which avoids the error.
Common mistake Calling pop without checking whether the stack has items
What it looks likeA loop that always calls pop, even when the stack has already been emptied.
Why it failsPopping from an empty stack is an error, so the program fails at that point.
Do this insteadCall isEmpty first and only pop when it returns false.
Common mistake Expecting to read a lower item directly
Why it failsOnly the top item is accessible at any time, so a lower item cannot be taken out until everything above it is removed.
Do this insteadThink of removal as strictly top-first and plan the order of pops accordingly.
Measuring the Size of a Stack Problem
To analyze how long a stack operation takes, we need a way to measure the size of the problem. For stacks the natural choice is the number of items currently on the stack. Call that number n. The question then becomes how the running time of push or pop grows as n grows. Keeping this measure in mind lets us compare the two ways a stack can be built.
Before choosing an implementation, it helps to ask a practical question: when a single stack operation runs, how much work could it end up doing, and does that amount of work depend on how full the stack already is? The answer differs between a linked list and an array, and the difference is more subtle than simply fast versus slow.
Linked List Implementation: Constant-Time Operations
For a linked list implementation, the worst-case run time of both push and pop is Theta(1). In plain terms, the run time is bounded by some fixed constant that does not depend on how many items the stack holds. Whether the stack has three items or three million, a single push or pop finishes within the same fixed amount of work.
The reason is visible in the structure of the operations. Each one is carried out by a handful of simple assignments that update the links at the top of the stack. Nothing in those steps requires visiting the other items. The total number of items on the stack never enters the calculation, so it cannot make the operation slower.
Array Implementation: The Full-Array Push
An array has a fixed amount of storage. Most pushes simply place a new item into the next free slot, and for these the run time is Theta(1). The trouble comes when the array is full and there is no free slot left. At that moment the implementation cannot simply write one more item, so it must make room in a different way.
The method is to create a new, larger array and copy every existing stack item into it, after which the new item can be placed. Copying takes time in proportion to the number of items already on the stack. Because the copying loop touches each of the n items, a push that triggers it has a worst-case run time of Theta(n).
In the diagram, the push that finds no free slot is the only one that triggers the copy. Every ordinary push onto an array with room left writes into the next free slot and does not copy anything. That single costly push is the source of the Theta(n) worst case.
Worst Case Versus Average Case
The worst case tells us how bad one operation can be. The average case tells us what to expect over a sequence of operations. For the array implementation these two measures give different pictures. The worst case of a single push is Theta(n), but the source notes that this worst case occurs only rarely. Because of that rarity, the average run time of push on an array remains Theta(1).
This is why worst-case and average-case claims should always be stated separately. Saying that array push is Theta(1) is true on average, but saying it is Theta(1) in the worst case would be false, because a single full-array push costs Theta(n).
Comparing the Two Implementations
Placing the two implementations side by side makes the contrast clear. The linked list keeps every push and pop at a fixed cost regardless of stack size. The array keeps ordinary pushes cheap but accepts one expensive case, the push that finds the array full. Neither implementation is better in every respect; each trades one kind of predictability for another.
| Measure | Linked list | Array |
|---|---|---|
| Push, worst case | Theta(1) | Theta(n), when the array is full |
| Push, average case | Theta(1) | Theta(1) |
| Pop, worst case | Theta(1) | Not covered in the source pack |
Run times for stack operations, as stated in the source material
Practice: Predict the Costly Push
An array-based stack has room for 4 items and currently holds 4 items. Predict which push is the costly one: pushing a fifth item, or pushing a sixth item after the array has been expanded and has free slots. Then state the worst-case cost of the costly push and the average-case cost of pushes in general.
Hints
- Ask whether the push has a free slot to write into.
- The worst case is the full-array push, which copies all n existing items.
- The average case stays Theta(1) because the full-array case is rare.
Key Takeaways on Stack Operations
- 1A stack allows access only to its top item, so an item lower down can be removed only after every item above it has been popped.
- 2push adds to the top, pop removes and returns the top item, and
isEmptyreports whether the stack has no items. - 3Popping from an empty stack is an error, so checking
isEmptybefore pop is the safe pattern. - 4A linked list gives Theta(1) worst-case time for push and pop, while an array gives Theta(1) average-case push but Theta(n) worst-case push when the array is full.
At a glance
- Only the top item of a stack is accessible, so removal happens in last-in, first-out order.
- The core operations are push, pop, and
isEmpty, and pop on an empty stack is an error. - The number of items on a stack, n, is the measure of problem size for run time analysis.
- A linked list implementation has Theta(1) worst-case push and pop; an array implementation has Theta(1) average-case push but a Theta(n) worst-case push when full.