用std::stack因其LIFO语义清晰且禁止不安全操作;括号匹配需四次判空:遇右括号前、top前、pop前、遍历后;映射右括号到左括号用unordered_map;空串合法,全左括号需终态判空。

为什么用 std::stack 而不是 std::vector 或 std::deque
括号匹配本质是后进先出(LIFO)行为:最近遇到的左括号必须最先被右括号闭合。用 std::stack 不仅语义清晰,还能天然屏蔽不安全操作——比如它不提供 operator[] 或迭代器遍历,避免误用索引访问或反向弹出。
若强行用 std::vector 模拟栈,容易写出 v.back() + v.pop_back() 组合,但一旦在空容器上调用 back() 会触发未定义行为;而 std::stack::top() 和 pop() 的调用前提需手动判空,这点必须由你控制。
常见错误现象:std::stack::top() 在空栈上调用 → 程序崩溃或静默错误(取决于 STL 实现)
- 始终在调用
top()或pop()前检查empty() - 不要依赖
size() == 0,empty()更高效且语义明确 -
std::stack默认底层是std::deque,无需显式指定;改用std::vector作容器仅在有连续内存偏好时才考虑,对括号匹配无实际收益
如何处理三种括号 '('、'['、'{' 的嵌套与交叉
关键不在“存什么”,而在“比什么”:入栈只存左括号字符本身,出栈时用哈希映射快速判断是否匹配。避免写一长串 if-else if 判断,也别用 switch(因为 char 是整型,语法上可行但可读性差且难扩展)。
立即学习“C++免费学习笔记(深入)”;
使用 std::unordered_map<char char></char> 建立右括号 → 对应左括号的映射:
std::unordered_map<char, char> pairs = {
{')', '('},
{']', '['},
{'}', '{'}
};
遍历时遇到右括号,先检查栈是否为空;再检查 stack.top() 是否等于 pairs[c];两者任一不满足即非法。
- 交叉场景如
"([)]":遇到')'时栈顶是'[',不等于pairs[')'](即'('),直接返回 false - 嵌套场景如
"{[()]}":每对右括号都精准匹配最近的左括号,栈自然清空 - 映射表必须覆盖所有右括号,漏掉一个(如没加
{'}', '{'})会导致查pairs['}']触发默认构造,返回'\0',比较失败
边界情况与性能影响:空字符串、纯左括号、Unicode 字符
空字符串 "" 是合法输入,应返回 true;全左括号如 "((((" 必须在遍历结束后检查栈是否为空——这是最容易漏掉的一步。
Unicode 字符(如中文括号、全角符号)不属于本算法处理范围。标准 ASCII 括号校验不应对 '(' 或 '[' 做任何假设。如果输入含此类字符,建议前置过滤或明确约定只处理 ASCII。
- 遍历完成后,必须检查
stack.empty();否则"((("会被误判为合法 - 单字符输入如
"("、")"都要能正确返回 false - 算法时间复杂度 O(n),空间最坏 O(n)(全左括号),无优化余地,也不需优化——这不是瓶颈
- 不要提前
reserve()栈容量:std::stack不暴露底层容器的reserve接口,且括号数量不可预知
完整逻辑中唯一不能省略的四次判空
整个流程里有且仅有四个位置必须显式判空,少一个就可能崩或逻辑错:
- 遇到右括号前:检查栈是否为空(空栈遇右括号必非法)
- 调用
top()前:即使刚判过空,也要再确认——多线程或宏展开可能引入干扰(虽然此处单线程,但养成习惯) - 调用
pop()前:和top()同理,pop()对空栈是未定义行为 - 循环结束后:检查栈是否为空(残留左括号 = 未闭合)
这四个判空点,是调试时 Segmentation fault 或逻辑错误最常出现的位置。写完务必对照输入 "", "(", ")", "([]", "([)]" 手动走一遍栈状态变化。


















