In Part 1 we explored why List<T> isn’t always the best choice and dove into LinkedList<T>. In this Part 2 sequel, we’ll focus on Stacks—a Last-In-First-Out (LIFO) collection that shines in scenarios like undo systems, depth-first traversals, and nested state machines.
Understanding Stacks in Unity
What is a Stack?
A Stack<T> is a dynamic, LIFO data structure. You can only add or remove items at the “top” of the stack. The primary operations are:
- Push(T item): Place an item on top.
- Pop(): Remove and return the item from the top.
- Peek(): Inspect the top item without removing it.
Internally, .NET’s Stack<T> uses an array that grows by doubling its size when capacity is exceeded—providing O(1) amortized Push/Pop.
When to Use Stacks in Unity
Use stacks whenever you need to reverse or backtrack operations in a strict LIFO order:
- Undo/Redo Systems: Record commands or states so the last action can be undone first.
- Depth-First Searches: Perform graph or tree traversals without recursion.
- State Machines & Nested Behaviors: Manage nested UI menus, game modes, or AI behaviors in a push/pop style.
- Pooling & Resource Stacks: Quickly retrieve and return objects (e.g., bullets, particle effects).
Example: Building an Undo System with Stack<T>
Imagine a simple action interface and history manager:
// IAction.cs
public interface IAction {
void Execute();
void Undo();
}
// HistoryManager.cs
using System.Collections.Generic;
using UnityEngine;
public class HistoryManager : MonoBehaviour {
private Stack<IAction> undoStack = new Stack<IAction>();
private Stack<IAction> redoStack = new Stack<IAction>();
public void DoAction(IAction action) {
action.Execute();
undoStack.Push(action);
redoStack.Clear();
}
public void Undo() {
if (undoStack.Count == 0) return;
var action = undoStack.Pop();
action.Undo();
redoStack.Push(action);
}
public void Redo() {
if (redoStack.Count == 0) return;
var action = redoStack.Pop();
action.Execute();
undoStack.Push(action);
}
}
Analyzing the Example and Performance Considerations
Key Takeaways
- Strict LIFO Order: Ensures the last action is always undone first.
- Constant-Time Operations:
Push,Pop, andPeekare allO(1)amortized. - Memory Growth: Internally doubles capacity, so occasional allocations occur but amortized cost stays low.
Stack vs. List
Stack Advantages:
- Enforces LIFO discipline—no accidental random access.
- Faster push/pop than inserting/removing at the end of a
List<T>when capacity is sufficient. - Simplifies code for nested or reversible operations.
List Advantages:
- Supports random access (
list[index]). - Better for collections where you need to iterate in arbitrary order.
- More flexible for mixed operations—insertions, deletions, lookups.
Conclusion: Choosing the Right Structure
When your Unity project demands strict LIFO behavior—like undo systems, DFS traversals, or nested states—Stack<T> is the clear winner. For everything else, weigh its constraints against the flexibility of List<T> or LinkedList<T>.
In Part 3 we’ll explore Queue<T> and real-time FIFO scenarios to further sharpen your data-structure toolkit.
