C++ 实现字符串的逆波兰表达算法及其语法树构建核心解析【详解】

秋磊君_9776

秋磊君_9776

2026-05-12

712人浏览

原创

逆波兰表达式安全求值需严格分词、运算符优先判别、栈大小检查及除零防护;调试时可用vector替代stack;扩展支持一元负号需上下文识别,浮点数需variant与from_chars解析。

c++ 实现字符串的逆波兰表达算法及其语法树构建核心解析【详解】

一、基于 std::stack 的逆波兰表达式安全求值实现

如果您尝试对一个以空格分隔的字符串形式输入的逆波兰表达式进行求值,但程序在运行时崩溃或返回错误结果,则很可能是由于 token 类型误判、弹栈顺序错误或未检查栈大小所致。以下是解决此问题的步骤:

1、使用 std::istringstream 或手动跳过空白字符的方式将输入字符串切分为 tokens 向量,确保 "-123"、"42" 等完整数字不被拆解。

2、遍历每个 token,先严格比对是否为 "+"、"-"、"*"、"/" 四个运算符字符串之一;仅当不匹配时才进入数字解析分支。

3、对非运算符 token 调用 std::stoi(token) 进行转换,该函数原生支持带符号整数(如 "-5"、"+42"),无需额外处理负号逻辑。

4、遇到运算符时,先检查 std::stack::size() >= 2,否则抛出 runtime_error;满足条件后执行:int b = st.top(); st.pop(); int a = st.top(); st.pop();。

5、对除法操作,在计算前立即判断 if (b == 0),并抛出 "division by zero" 异常;减法与除法必须保持 a op b 语义,不可颠倒。

二、手写 vector 模拟栈以支持调试与中间状态观察

当需要验证每一步计算过程、定位某次压栈/弹栈异常或排查非法 token 导致的静默失败时,std::stack 因缺乏遍历接口而难以调试。改用 std::vector 可显式控制栈顶索引并打印全部内容。

1、声明 std::vector stack; 替代 std::stack,所有 push 操作改为 stack.push_back(value)。

2、弹出右操作数时使用 int b = stack.back(); stack.pop_back();,再弹左操作数:int a = stack.back(); stack.pop_back();。

3、每次关键操作后可插入 for (auto x : stack) std::cout 输出当前栈状态。

4、在运算符处理入口处添加 if (stack.size() 。

5、对非法 token(如 "abc" 或空字符串),在 stoi 前加长度与首字符校验:if (token.empty() || (token.size() == 1 && !std::isdigit(token[0]))) throw std::invalid_argument("invalid token: " + token);。

三、构建抽象语法树(AST)节点结构与递归构造逻辑

若需从逆波兰表达式反向生成语法树(例如用于可视化、类型检查或代码生成),不能直接复用求值栈逻辑,而应维护节点指针栈,在遇到运算符时合并子树根节点。

1、定义 AST 节点结构:struct Node { std::string val; Node* left = nullptr; Node* right = nullptr; explicit Node(const std::string& v) : val(v) {} };

2、初始化 std::stack node_stack;,遍历 tokens:若为数字,new Node(token) 并压栈;若为运算符,弹出两个节点作为 right 和 left 子树。

3、构造新节点时,Node* op_node = new Node(token); op_node->right = right; op_node->left = left;,注意 right 先弹出,故作为右子树。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

4、将 op_node 压入 node_stack;循环结束后,栈中唯一节点即为 AST 根节点。

5、为防止内存泄漏,应在析构函数或 RAII 容器中递归 delete 所有节点,或改用 std::unique_ptr 管理所有权。

四、使用 std::from_chars 替代 std::stoi 实现无异常数字解析

在高可靠性场景下,std::stoi 抛出异常可能打断控制流,且无法区分数值溢出与格式错误。std::from_chars 是 C++17 引入的零开销解析接口,返回错误码而非异常,更适合嵌入式或服务端批量处理。

1、为每个 token 声明 std::from_chars_result res; 与目标变量 long long temp_val = 0;。

2、调用 res = std::from_chars(token.data(), token.data() + token.size(), temp_val);。

3、检查 if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range),触发自定义错误处理路径。

4、确认解析完整:if (res.ptr != token.data() + token.size()) 表示存在尾随非法字符(如 "123abc"),应视为非法 token。

5、将 temp_val 转为 int 前,增加 if (temp_val INT_MAX) 判断溢出,避免截断静默错误。

五、支持一元负号与浮点数的扩展 token 分类机制

标准逆波兰表达式规范通常不包含一元运算符,但实际输入可能含 "-5"(操作数)与 "5 -"(二元减)共存。需通过上下文识别一元负号,避免将其误判为减法运算符。

1、预扫描 tokens 序列,记录每个 token 的前驱 token 类型:若前驱为空、为 "(" 或为运算符,则当前 "-" 视为一元负号。

2、对识别为一元负号的 token,跳过运算符分支,直接按数字解析(如 stoi("-5")),并在 AST 构造中生成 UnaryMinus 节点而非 BinaryOp。

3、若需支持浮点数,将 token 判定逻辑扩展为:先尝试 std::from_chars 解析 double,失败再试整数,最后判运算符。

4、在 vector 模拟栈中,统一使用 std::variant 存储值类型,配合 std::holds_alternative 和 std::get 提取。

5、对浮点除法,禁用向零截断,直接使用 / 运算符,并在 AST 中标记 type = FLOAT,确保后续类型推导一致性。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2288

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1039

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

347

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

426

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

600

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1429

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1237

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1345

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习