news 2026/8/16 21:39:27

第33篇 STL之stack与queue:BFS/DFS的标配数据结构,面试手写不过分吧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第33篇 STL之stack与queue:BFS/DFS的标配数据结构,面试手写不过分吧

上篇聊了map和unordered_map,今天看两个"受限"容器——stack和queue。

说它们受限,是因为它们不支持遍历,不能随机访问,只能在特定的位置操作元素。但正是这种限制,让它们在特定场景下非常高效。

面试里考stack和queue,通常和算法题绑在一起。"用BFS求最短路径""实现一个栈的排序""用两个栈实现队列"……这些题你都得熟悉stack和queue的接口。

stack:后进先出

stack的接口非常简单:

std::stack<int> s; s.push(1); // 入栈 s.push(2); s.push(3); cout << s.top(); // 3,查看栈顶 s.pop(); // 弹出3 cout << s.top(); // 2 cout << s.size(); // 2

push和pop都在栈顶操作,后进先出(LIFO)。没有begin()、end(),不能遍历。

stack的默认底层容器是deque,但你可以指定用vector或list:

std::stack<int, std::vector<int>> s; // 用vector做底层 std::stack<int, std::list<int>> s; // 用list做底层

大部分时候用默认的deque就够了。如果你确定stack里的元素数量会很多且不需要在中间操作,用vector底层可能缓存更友好。

stack在算法面试中的应用

stack在面试算法题里出现频率极高。

最经典的:用stack实现DFS(深度优先搜索)。在机器人开发里,DFS常用于地图探索、迷宫求解。

// 网格地图的DFS探索 void dfs(vector<vector<int>>& grid, int r, int c) { int rows = grid.size(), cols = grid[0].size(); stack<pair<int,int>> s; s.push({r, c}); while (!s.empty()) { auto [cr, cc] = s.top(); s.pop(); if (cr < 0 || cr >= rows || cc < 0 || cc >= cols) continue; if (grid[cr][cc] == 1) continue; // 已访问或障碍物 grid[cr][cc] = 1; // 标记已访问 // 四个方向入栈 s.push({cr-1, cc}); s.push({cr+1, cc}); s.push({cr, cc-1}); s.push({cr, cc+1}); } }

还有个经典面试题:"有效的括号匹配"。用stack来做,遇到左括号入栈,遇到右括号检查栈顶是否匹配。

bool isValid(const string& s) { stack<char> st; for (char c : s) { if (c == '(' || c == '[' || c == '{') { st.push(c); } else { if (st.empty()) return false; if (c == ')' && st.top() != '(') return false; if (c == ']' && st.top() != '[') return false; if (c == '}' && st.top() != '{') return false; st.pop(); } } return st.empty(); }

queue:先进先出

queue的接口也很简单:

std::queue<int> q; q.push(1); // 入队(尾部) q.push(2); q.push(3); cout << q.front(); // 1,查看队首 cout << q.back(); // 3,查看队尾 q.pop(); // 弹出1(队首)

push在队尾,pop在队首,先进先出(FIFO)。同样不能遍历。

queue的默认底层容器也是deque。

queue在算法面试中的应用

queue最经典的用途就是BFS(广度优先搜索)。在机器人开发里,BFS用于求最短路径、 flood fill、层级遍历。

// 网格地图的BFS求最短路径 int shortestPath(vector<vector<int>>& grid, pair<int,int> start, pair<int,int> end) { int rows = grid.size(), cols = grid[0].size(); queue<pair<int,int>> q; q.push(start); grid[start.first][start.second] = 1; // 标记已访问 int steps = 0; while (!q.empty()) { int size = q.size(); for (int i = 0; i < size; i++) { auto [r, c] = q.front(); q.pop(); if (r == end.first && c == end.second) return steps; int dr[] = {-1, 1, 0, 0}; int dc[] = {0, 0, -1, 1}; for (int d = 0; d < 4; d++) { int nr = r + dr[d], nc = c + dc[d]; if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] == 0) { grid[nr][nc] = 1; q.push({nr, nc}); } } } steps++; } return -1; // 不可达 }

BFS保证找到的是最短路径(在无权图中),因为它是按层级扩展的。DFS不保证最短,但内存占用通常更小。

priority_queue:带优先级的队列

面试里还有个常客:priority_queue(优先队列)。它不是FIFO,而是每次弹出的都是当前最大(或最小)的元素。

// 默认大顶堆 priority_queue<int> max_heap; max_heap.push(3); max_heap.push(1); max_heap.push(5); cout << max_heap.top(); // 5 // 小顶堆 priority_queue<int, vector<int>, greater<int>> min_heap; min_heap.push(3); min_heap.push(1); min_heap.push(5); cout << min_heap.top(); // 1

priority_queue底层是vector实现的堆结构,插入和弹出都是O(log N)。

在机器人开发里,priority_queue是A*和Dijkstra算法的核心数据结构。每次从open list里取代价最小的节点,用priority_queue天然合适。

// Dijkstra算法核心 priority_queue<pair<double, int>, vector<pair<double, int>>, greater<>> pq; pq.push({0.0, start_node}); while (!pq.empty()) { auto [cost, node] = pq.top(); pq.pop(); // 处理node... }

补充一个面试容易忽略的知识点:stack和queue在STL里其实是容器适配器,不是独立的容器。它们底层默认分别用deque实现,但你可以通过模板参数指定其他底层容器。比如stack<int, vector<int>>用vector做底层,queue<int, list<int>>用list做底层。面试时如果你能说出"stack和queue是适配器而不是容器",面试官会觉得你对STL的架构理解得很透彻。在机器人开发里,有时候你需要一个线程安全的队列,做法就是继承std::queue然后加锁,或者用std::deque配合std::mutex封装一个生产者消费者队列,这在多传感器数据融合的场景里非常常见。

给正在准备面试的你一点建议

stack和queue本身接口简单,面试主要考你怎么用它们解决问题。

必须掌握的:stack的LIFO特性用于DFS和括号匹配,queue的FIFO特性用于BFS,priority_queue用于Dijkstra和A*。

面试手写代码的时候,BFS和DFS是必须闭着眼写出来的。特别是BFS的层级遍历模板(每次处理一层的所有节点),很多候选人写着写着就乱了。

下篇讲迭代器模式——STL的灵魂设计思想。


如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。

「机器人软件开发面试·从入门到精通」连载系列

上一篇:第32篇 STL之map与unordered_map——底层红黑树vs哈希表

下一篇预告:第34篇 迭代器模式——STL的灵魂设计思想

有任何问题欢迎评论区留言,我会尽量回复。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/16 21:36:07

FastApi进阶

中间件中间件是一个再每次请求进入fastapi时都会执行的函数&#xff0c;他在请求到达实际路径操作之前执行&#xff0c;并且再相应返回客户端之前再运行一次&#xff0c;执行顺序按代码顺序自底向上执行具体使用app.middleare("http") async def middleare(request,c…

作者头像 李华
网站建设 2026/8/16 21:35:43

一文速通GPU版FFmpeg视频转码的安装使用

目录 写在前面 一、FFmpeg 版本 二、完整安装步骤 1. 安装编译依赖 2.安装nv-codec-headers SDK 12.0 3.如果需要 x264/x265&#xff08;软件编码备用&#xff09; 4. 下载 FFmpeg 6.0 源码 5. 配置编译选项 6. 编译并安装 三、 验证安装 1.查看FFmpeg版本 2.检查 N…

作者头像 李华
网站建设 2026/8/16 21:31:43

传统BIOS引导黑苹果实战:老硬件安装macOS Monterey完整指南

1. 项目缘起&#xff1a;为什么今天还要折腾传统BIOS引导的黑苹果&#xff1f;如果你在2024年还在搜索“黑苹果传统BIOS引导安装”&#xff0c;大概率和我当初一样&#xff0c;手里正攥着一台有些年头的“老伙计”。它可能是陪伴你度过大学时光的“神船”&#xff0c;也可能是公…

作者头像 李华
网站建设 2026/8/16 21:31:35

无线传输模块概述

以下按主流技术路线分类,逐一讲解无线传输模块的技术特征、适用场景、价格区间与典型案例。所有价格为 2025-2026 年国内市场参考值,受采购批量、封装等级、认证资质影响会有波动,标注均附数据来源。 一、WiFi 无线模块(含 WiFi + 蓝牙二合一) 1. 核心技术特征 工作频段:…

作者头像 李华
网站建设 2026/8/16 21:29:26

Python 快速上手(Java 开发者版)

笔者本人是有 Java 基础&#xff0c;这篇文档只讲 Python 的不同之处和刷题/开发中最实用的东西。 目录 环境搭建 语法速览&#xff1a;一张表看懂 Java vs Python 内置数据结构&#xff08;刷题核心&#xff09; 列表推导式 & 生成器&#xff08;Python 大招&#xff0…

作者头像 李华