C++基于调度场算法的基本四则运算计算器

📅 发布时间:2026/7/4 1:09:54 👁️ 浏览次数:
C++基于调度场算法的基本四则运算计算器
本文为原创技术教程完整代码可直接编译运行适合C入门、数据结构学习者练手参考前言在日常开发与编程学习中四则运算表达式解析是栈数据结构、编译原理词法分析的经典入门实践。我们日常书写的34*2/(1-5)这类中缀表达式符合人类的阅读习惯但对计算机而言存在运算符优先级、括号嵌套等处理难题无法直接顺序计算。本文将基于C实现一套完整的四则运算计算器核心采用调度场算法Shunting-yard Algorithm完成中缀表达式到后缀表达式逆波兰表达式的转换再通过栈结构实现后缀表达式的高效计算。本文代码完整可运行注释清晰可直接复制到本地编译测试也可用于课程作业、个人练手项目。一、核心原理详解1.1 中缀表达式 vs 后缀表达式中缀表达式运算符位于两个操作数中间如12*3需要依赖括号和运算符优先级决定计算顺序人类易读计算机难处理。后缀表达式逆波兰表达式运算符位于两个操作数之后如1 2 3 * 无括号、无优先级歧义严格遵循从左到右的顺序计算完美适配计算机的栈结构处理逻辑。示例中缀表达式34*2/(1-5)转换为后缀表达式为3 4 2 * 1 5 - / 计算顺序完全符合数学规则。1.2 调度场算法中缀转后缀核心调度场算法由计算机科学家Dijkstra提出专门用于中缀表达式到后缀表达式的转换核心通过一个输出队列一个运算符栈实现核心步骤如下从左到右遍历中缀表达式的每个字符若为数字直接加入输出队列若为左括号(直接压入运算符栈若为右括号)将栈顶运算符依次弹出并加入输出队列直到遇到左括号弹出左括号并丢弃不加入输出若为运算符将栈中优先级大于等于当前运算符的栈顶元素依次弹出并加入输出队列直到栈空或遇到左括号再将当前运算符压入栈遍历结束后将栈中剩余的所有运算符依次弹出加入输出队列。1.3 后缀表达式的计算逻辑后缀表达式的计算完全依赖栈结构步骤极简且无歧义从左到右遍历后缀表达式的每个token数字/运算符若为数字直接压入数字栈若为运算符连续弹出栈顶两个元素先弹出的为右操作数b后弹出的为左操作数a执行a 运算符 b将计算结果压回栈中遍历结束后栈中仅剩的一个元素就是表达式的最终计算结果。关键提醒减法、除法对操作数顺序敏感必须严格遵循左操作数 运算符 右操作数的顺序否则会出现计算错误。二、代码模块逐行详解2.1 头文件与全局配置首先引入所需的标准库并定义运算符优先级映射表使用unordered_map实现O(1)时间复杂度的优先级查询const修饰保证全局只读避免误修改。#includeiostream#includestack// 栈容器用于运算符暂存与数字计算#includestring// 字符串处理存储表达式#includeunordered_map// 无序映射存储运算符优先级#includesstream// 字符串流用于后缀表达式的token分割// 运算符优先级映射表数字越大优先级越高conststd::unordered_mapchar,intPRECENCE{{*,2},// 乘除优先级高于加减{/,2},{,1},{-,1},{(,0}// 左括号优先级最低仅作为边界标识};2.2 中缀表达式转后缀表达式实现核心函数tolastStr完整实现调度场算法同时解决了新手常见的多位数拆分、栈空访问崩溃、括号处理异常等问题。核心步骤遍历中缀表达式若为数字则直接加入输出队列若为符号则先与符号栈栈顶循环判断优先级将小于等于其的元素依次出栈进入输出队列最后再入栈特殊的遇到右括号时直接将栈顶元素循环出栈直到遇到左括号最后遍历完成后将符号栈中元素全部出栈进入输出队列这个输出队列就是转化的后缀表达式。std::stringtolastStr(std::string str){std::stackcharop_stack;// 运算符栈临时存放运算符std::string lastStr;// 输出队列存储最终的后缀表达式// 遍历输入的中缀表达式for(constchari:str){// 1. 处理数字直接加入输出队列if(0ii9){lastStr.push_back(i);}// 2. 处理非数字字符运算符、括号else{// 给数字加空格分隔解决多位数拆分问题如123不会被拆成1、2、3if(!lastStr.empty()lastStr.back()! ){lastStr.push_back( );}// 2.1 处理左括号直接入栈if(i(){op_stack.push(i);}// 2.2 处理右括号弹出运算符直到左括号elseif(i)){while(!op_stack.empty()op_stack.top()!(){lastStr.push_back(op_stack.top());lastStr.push_back( );op_stack.pop();}// 弹出左括号并丢弃不加入输出队列if(!op_stack.empty()){op_stack.pop();}}// 2.3 处理四则运算符按优先级处理栈else{// 弹出栈中优先级当前运算符的元素直到栈空/遇到左括号// 使用at()而非[]避免不存在的运算符导致未定义行为while(!op_stack.empty()op_stack.top()!(PRECENCE.at(i)PRECENCE.at(op_stack.top())){lastStr.push_back(op_stack.top());lastStr.push_back( );op_stack.pop();}// 当前运算符入栈op_stack.push(i);}}}// 遍历结束弹出栈中剩余的所有运算符while(!op_stack.empty()){if(!lastStr.empty()lastStr.back()! ){lastStr.push_back( );}lastStr.push_back(op_stack.top());op_stack.pop();}returnlastStr;}关键细节说明多位数处理通过空格分隔数字与运算符后续通过 stringstream 可正确拆分多位数解决了新手代码仅支持个位数的痛点​健壮性优化所有栈操作前都做了 !op_stack.empty() 非空判断避免栈空访问导致的程序崩溃​安全访问使用 PRECENCE.at(i) 而非 [] 访问优先级 at() 会做边界检查遇到非法运算符时抛出异常避免未定义行为​括号处理严格遵循调度场算法规则右括号仅弹出到左括号左括号不会进入输出队列。2.3 后缀表达式计算实现函数 result_math 实现后缀表达式的计算通过 stringstream 自动分割空格分隔的token逻辑清晰适配多位数场景。利用流的自动空白字符分割判断快速切分获取 token 之后再逐一判断 token若为数字则直接入栈若为符号则依次取出栈两个数字进行计算后出栈的为左计算单元最后将计算完成的结果入栈以此类推到最后留在栈中的一个元素就是计算结果。intresult_math(std::string str){std::stackintnum_stack;// 数字栈存储操作数与中间结果std::stringstreamss(str);// 字符串流自动按空格分割tokenstd::string token;// 遍历每个tokenwhile(sstoken){// 1. 处理运算符弹出两个操作数计算if(token||token-||token*||token/){// 注意顺序先弹出的是右操作数b后弹出的是左操作数aintbnum_stack.top();num_stack.pop();intanum_stack.top();num_stack.pop();// 按运算符执行计算结果入栈if(token)num_stack.push(ab);elseif(token-)num_stack.push(a-b);elseif(token*)num_stack.push(a*b);elseif(token/)num_stack.push(a/b);// 整数除法向零取整}// 2. 处理数字转为int后入栈else{num_stack.push(std::stoi(token));}}// 栈中剩余的唯一元素即为最终结果returnnum_stack.top();}2.4 主函数入口逻辑主函数实现用户输入、表达式转换、结果输出的完整流程增加了基础的输入合法性判断。intmain(intargc,char*argv[]){std::cout请输入计算表达式 :std::endl;std::string midStr,lastStr;std::cinmidStr;// 基础输入校验空输入直接退出if(midStr.size()0)return1;// 中缀转后缀lastStrtolastStr(midStr);// 输出中间结果与最终计算结果std::cout后缀表达式lastStrstd::endl;std::cout计算结果result_math(lastStr)std::endl;return0;}三、当前版本局限与扩展优化方向4.1 当前版本局限仅支持正整数的四则运算不支持浮点数、负数输入​仅支持 、-、*、/ 四个基础运算符不支持取模、幂运算等​异常处理不完善除零错误、括号不匹配、非法字符输入会导致程序异常​仅支持整数除法向零取整无小数精度处理。4.2 进阶扩展优化方案支持浮点数运算将操作数类型从 int 改为 double 数字转换函数从 std::stoi 改为 std::stod 适配小数输入与浮点计算​支持负数处理增加负号判断逻辑识别表达式开头的 - 、括号后的 - 为负号而非减法运算符​完善异常处理增加 try-catch 异常捕获处理除零错误、括号不匹配、非法字符、表达式格式错误等场景提升程序健壮性​扩展运算符支持新增取模 % 、幂运算 ^ 、开方等运算符更新优先级映射表与计算逻辑​五、总结本文通过C完整实现了一套基于调度场算法的四则运算计算器核心覆盖了栈数据结构的经典应用、调度场算法的工程实现、表达式解析的核心逻辑三大核心知识点。该项目是数据结构与算法入门的绝佳练手案例既可以帮助新手理解栈的应用场景也可以作为编译原理词法分析的入门实践。