选择原则:后进先出用栈,先进先出用队列,总是取最高或最低优先级用堆。三者都在限制“下一个处理谁”。
Stack:后进先出
栈适合 UI 返回、撤销记录、非递归 DFS 和临时解析状态。
Push、Pop、Peek 都是 O(1)。如果撤销操作还需要恢复数据,应把命令或快照压栈,而不只是名称。Queue:先进先出
队列适合消息缓冲、生成请求、逐帧预算和 BFS:
把大量工作分帧处理能避免单帧尖峰,但要给队列设置最大长度和过载策略,否则生产速度高于消费速度时会持续占用内存。
Queue 实现 BFS
BFS 按层访问,适合最少步数、层级 UI 和邻近扩散。
二叉堆:动态优先级
队列只能保证先来先处理。A* 寻路、AI 调度和定时任务需要反复取最小代价元素,常用二叉最小堆:
插入和弹出都是 O(log n),查看堆顶是 O(1)。Unity 当前运行时配置不一定提供 .NET 的
PriorityQueue<TElement,TPriority>,项目应以实际 API 兼容级别为准。环形缓冲区
固定容量的网络快照、输入历史和音频采样更适合环形缓冲区:
- 内存固定,不会无限增长
- 头尾索引循环复用数组
- 可选择覆盖最旧数据或拒绝新数据
普通 Queue 更通用;环形缓冲区适合容量明确、追求零扩容的热路径。
复杂度
结构 | 加入 | 取出 | 典型用途 |
Stack | O(1) | O(1) | 撤销、返回、DFS |
Queue | O(1) | O(1) | BFS、消息、分帧任务 |
Binary Heap | O(log n) | O(log n) | A*、调度器、最近目标 |
常见坑
- 对空集合直接
Pop或Dequeue。
- 队列无上限,消费者跟不上生产者。
- 用 List 每次排序模拟优先队列,造成 O(n log n) 重复工作。
- 堆中优先级变化后不重新调整位置。
- 在多线程之间共享普通 Stack/Queue 而不做同步。