A Stack<T> is a pile: you put items on top with Push and take them off the top with Pop, so the last item in is the first one out (LIFO). Only the top is reachable, and every operation on it takes constant time.
Push, Pop and Peek
Output:
On top: green
Count: 3
Took green
On top: red
Took red
Took blue
Count: 0
green was pushed last, so it comes off first. Peek returns the top without changing the stack, which is how you inspect what Pop would give you before deciding to take it.
The empty stack exception and TryPop
Popping or peeking at an empty stack throws InvalidOperationException. This shows up most often in parsers and algorithms fed with input that has more closing items than opening ones.
Output:
Caught InvalidOperationException
True 10
False 0
TryPop and TryPeek (.NET Core 2.0 and later) return false on an empty stack and set the out variable to the default value, 0 here. On .NET Framework, check Count > 0 first.
Iteration order: top first
Enumerating a stack does not remove anything, and it goes from the top down, in the order Pop would return the items:
Output:
checkout products home
checkout > products > home
True
home
checkout
The reversed copy catches people out: the constructor takes any IEnumerable<T> and pushes its items in order, and a stack enumerates top first, so the old top ends up at the bottom of the copy. Reversing the sequence first (LINQ's Reverse() returns the items bottom first) gives a copy with the same top.
Pushing a list of items onto a new stack also reverses them, which is a quick way to reverse a sequence: new Stack<char>("hello") pops back o, l, l, e, h.
Example: an undo history
Editors keep every change on a stack. Undo pops the most recent change and reverts it; redo keeps a second stack of undone changes.
Output:
Hello, world!
Hello, world
Hello
Hello, world
Storing whole snapshots is the simplest version. Real editors push small command objects instead (what was inserted, and where), each with a method to reverse itself, but the two stacks work the same way.
Example: balanced brackets
Checking that (, [ and { are closed in the right order is the standard stack exercise, and the same logic sits inside every compiler and JSON parser.
Output:
"f(a[i], {x: 1})" -> True
"(]" -> False
"((a)" -> False
"a)b(" -> False
"" -> True
The three failure checks correspond to the three ways brackets go wrong: a closer with nothing open (a)b(, caught by Count == 0 instead of an exception from Pop), a closer of the wrong kind ((]), and openers never closed (((a), caught by the final check).
Other uses
- Depth first search. Replace the queue in a breadth first search with a stack and the traversal goes deep before wide. An explicit stack also replaces recursion when the input is deep enough to risk a
StackOverflowException, which cannot be caught. - Evaluating expressions. Postfix notation (
3 4 + 2 *) is evaluated by pushing numbers and popping two for each operator. - Backtracking. Navigation history, maze solving and parser states push a position and pop back to it on a dead end.
See Queue for the first in, first out counterpart.
Stack vs Queue vs List
Stack<T> | Queue<T> | List<T> | |
|---|---|---|---|
| Order out | Newest first | Oldest first | Any, by index |
| Add | Push | Enqueue | Add, Insert |
| Remove | Pop (top) | Dequeue (front) | Remove, RemoveAt |
| Look | Peek | Peek | list[i] |
| Safe variants | TryPop, TryPeek | TryDequeue, TryPeek | not needed |
For several threads, ConcurrentStack<T> in System.Collections.Concurrent offers Push, TryPop and TryPeek without locks.
Common mistakes
- Popping without checking. An empty stack throws
InvalidOperationException; checkCountor useTryPop. - Expecting
foreachto go from the first item pushed. It goes from the top. - Copying with
new Stack<T>(stack). The copy is reversed. - Pushing inside
foreachover the same stack. Throws; use awhile (stack.Count > 0)loop.
Frequently Asked Questions
What is a Stack in C#?
Stack<T> in System.Collections.Generic is a last in, first out (LIFO) collection. Push puts an item on top, Pop removes and returns the top item, and Peek returns the top item without removing it. All three run in constant time.
What happens when you Pop an empty stack in C#?
Pop and Peek throw InvalidOperationException when the stack is empty. Check stack.Count > 0 first, or use TryPop(out var item) and TryPeek(out var item), which return false instead of throwing (.NET Core 2.0 and later).
In what order does foreach go through a Stack?
From the top down: the most recently pushed item comes first, the same order Pop would return them. ToArray() uses the same order. A consequence is that new Stack<T>(otherStack) produces a reversed copy, because the constructor pushes the items in the order it enumerates them.
What is the difference between a Stack and a Queue in C#?
A Stack<T> returns the newest item first (last in, first out), while a Queue<T> returns the oldest item first (first in, first out). Use a stack for undo history, nested structures and depth first search; use a queue for processing work in arrival order and breadth first search.
How do I check for balanced brackets in C#?
Scan the string once. Push every opening bracket onto a Stack<char>. For every closing bracket, the stack must be non-empty and its top must be the matching opening bracket, which you then pop. The string is balanced when the scan ends with the stack empty.