队列的应用

队列 的核心特征是先进先出,适合保存“先到先处理”的对象,也适合按层次、按距离逐步扩展的过程。

树的层次遍历

层次遍历从根结点开始,按从上到下、从左到右的顺序访问结点。队列保存“已经发现但还没访问其孩子”的结点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void LevelOrder(BiTree root) {
if (root == NULL) return;

LinkQueue queue;
InitQueue(&queue);
EnQueue(&queue, root);

while (!QueueEmpty(queue)) {
BiTNode *node;
DeQueue(&queue, &node);
Visit(node);

if (node->lchild != NULL) EnQueue(&queue, node->lchild);
if (node->rchild != NULL) EnQueue(&queue, node->rchild);
}
}

队列保证先入队的上一层结点先被处理,因此孩子结点自然按层次展开。

图的广度优先遍历

广度优先遍历从某个顶点出发,先访问距离为 1 的邻接点,再访问距离为 2 的顶点,以此类推。队列保存“已访问但邻接点尚未扩展完”的顶点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void BFS(Graph graph, int start) {
bool visited[MAX_VERTEX_NUM] = {false};
LinkQueue queue;
InitQueue(&queue);

Visit(start);
visited[start] = true;
EnQueue(&queue, start);

while (!QueueEmpty(queue)) {
int vertex;
DeQueue(&queue, &vertex);

for (int neighbor = FirstNeighbor(graph, vertex);
neighbor >= 0;
neighbor = NextNeighbor(graph, vertex, neighbor)) {
if (!visited[neighbor]) {
Visit(neighbor);
visited[neighbor] = true;
EnQueue(&queue, neighbor);
}
}
}
}

若不使用 visited 标记,图中有环时会重复入队,甚至无法结束。

操作系统中的队列

操作系统中常用队列组织等待处理的对象:

  • 就绪进程队列:等待 CPU 调度的进程按规则排队。
  • 阻塞队列:等待某类事件或资源的进程排队。
  • 缓冲区队列:例如打印任务或输入输出数据按到达顺序等待处理。

这些场景的共同点是:对象到达有先后,处理资源有限,需要保存等待顺序。

易错点

  • 层次遍历和广度优先遍历都依赖队列,但一个面向树,一个面向图。
  • 图的 BFS 必须配合访问标记;树无环,通常不需要 visited
  • 队列只保证先进先出,具体调度策略可能还会叠加优先级、时间片等规则。