计算器——可支持小数的任意四则运算(中缀表达式转为后缀表达式算法)

中缀表达式转为后缀表达式的原理过程主要包括以下步骤:

1. 初始化两个栈,一个用于存储操作数,一个用于存储运算符。
2. 从左到右扫描中缀表达式的每个字符。
3. 如果遇到数字,则直接将其压入操作数栈。
4. 如果遇到运算符,则分两种情况处理:如果运算符优先级大于等于栈顶运算符的优先级,则将栈顶运算符弹出并压入后缀表达式,直到栈为空或者栈顶运算符的优先级低于当前运算符为止,然后将当前运算符压入栈;如果运算符优先级小于栈顶运算符的优先级,则直接将当前运算符压入栈。
5. 当表达式扫描完毕后,如果栈中仍有剩余的运算符,则将这些运算符依次弹出并压入后缀表达式。

6. 最后,后缀表达式中剩余的元素即为转换后的结果。

        需要注意的是,在实际应用中,可能还需要进行一些额外的处理,比如补全缺失的括号,以确保表达式的正确性。

 (括号法)

完整代码(注释都在代码中):

#include <iostream>//用于输入输出操作
#include <stack>//用于实现栈数据结构
#include <string>//用于处理字符串
#include <sstream>//用于字符串流操作
#include <cctype>//用于字符处理函数
#include <stdexcept>// 用于异常处理using namespace std;
//用于判断给定的字符是否为运算符。
//如果字符是加号、减号、乘号或除号,则返回 true,否则返回 false。
bool is_operator(char c) {return c == '+' || c == '-' || c == '*' || c == '/';
}//用于确定运算符的优先级。
//对于加号和减号,优先级为 1;对于乘号和除号,优先级为 2。其他字符的优先级为 0。
int precedence(char op) {if (op == '+' || op == '-') {return 1;}else if (op == '*' || op == '/') {return 2;}else {return 0;}
}//用于应用运算符并返回结果。
//根据传入的运算符,执行相应的加法、减法、乘法或除法操作,并返回结果。如果传入的运算符无效,则抛出运行时错误。
double apply_operator(double a, double b, char op) {switch (op) {case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/': return a / b;//如果某个函数执行失败,可以抛出一个 std::runtime_error 异常对象,并提供相应的错误信息。default: throw runtime_error("Invalid operator");}
}//用于计算给定的数学表达式。
//它使用两个栈来存储数字和运算符。
//数字栈用于存储操作数,运算符栈用于存储运算符。
double evaluate_expression(const string& expression) {stack<double> num_stack;stack<char> op_stack;//这个循环遍历整个表达式字符串。对于每个字符,根据其类型执行相应的操作。如果是空格,则跳过;//如果是数字或小数点,则解析出完整的数字并将其压入数字栈;//如果是运算符,则将其与运算符栈顶的运算符进行比较,并根据优先级决定是否立即应用运算符。//如果是左括号,则将其压入运算符栈;//如果是右括号,则将匹配的左括号弹出,并将括号内的表达式计算出来。//如果遇到无效字符,则抛出运行时错误。for (size_t i = 0; i < expression.length(); ++i) {//size_t 是一种无符号整数类型,使用 size_t 类型作为循环变量的类型是为了确保能够正确处理表达式的长度,并提高代码的可移植性。if (isspace(expression[i])) {//isspace(expression[i])用于处理输入的字符串,以便在对字符串进行处理之前先识别和处理其中的空白字符。// 执行了对字符串 expression 在索引 i 处的字符进行空白字符判断。//如果返回结果为 true,则表示该字符是空白字符;如果返回结果为 false,则表示该字符不是空白字符。continue;}/* 这段代码是一个条件判断和循环的代码块。它的作用是找到一个数字或小数点开始的连续字符序列。首先,使用 isdigit(expression[i]) || expression[i] == '.' 判断表达式 expression 在索引 i 处的字符是否为数字或小数点。如果是,则执行以下代码块。在代码块中,定义了一个新的变量 j 并将其初始化为 i。然后,使用一个循环来迭代从 j 开始的字符序列。在循环的每一次迭代中,首先检查 j 是否超出了字符串 expression 的长度,并且判断 expression[j] 是否是数字或小数点。如果是,就将 j 的值增加 1,继续下一次迭代。这个循环会一直持续,直到遇到一个不是数字或小数点的字符,或者到达了字符串 expression 的结尾。在循环结束后,变量 j 将指向字符序列的下一个位置。这段代码的目的是找到一个数字或小数点开始的连续字符序列,以便后续处理该数字或小数点。*/else if (isdigit(expression[i]) || expression[i] == '.') {size_t j = i;while (j < expression.length() && (isdigit(expression[j]) || expression[j] == '.')) {++j;}/*这段代码的作用是将找到的连续数字或小数点字符序列转换为一个双精度浮点数,并将其压入一个名为 num_stack 的栈中。首先,通过 expression.substr(i, j - i) 获取从索引 i 到索引 j - 1 的子字符串,该子字符串包含了找到的连续数字或小数点字符序列。然后,创建一个 stringstream 对象 ss 并将该子字符串传递给它。stringstream 类提供了一种将字符串转换为其他类型的数据的方法。接下来,使用 ss >> number 将 ss 中的字符串转换为一个双精度浮点数,并将其存储在变量 number 中。最后,将变量 number 压入名为 num_stack 的栈中,以便后续处理。最后一行的 i = j - 1 的目的是将变量 i 更新为 j - 1 的值,以便在循环的下一次迭代中,跳过已经处理过的字符序列。总之,这段代码的作用是将找到的连续数字或小数点字符序列转换为双精度浮点数,并将其存储在一个栈中,以便后续处理。*/double number;stringstream ss(expression.substr(i, j - i));ss >> number;num_stack.push(number);i = j - 1;}/* 这段代码用于处理表达式中的操作符。首先,通过调用 is_operator(expression[i]) 来判断当前字符 expression[i] 是否为操作符。如果是操作符,则进入一个循环。循环的条件是操作符栈 op_stack 不为空,并且栈顶操作符的优先级大于或等于当前操作符 expression[i] 的优先级。在循环中,首先从操作数栈 num_stack 中弹出栈顶的两个双精度浮点数,分别存储在变量 b 和 a 中。这两个操作数分别代表了运算符左侧和右侧的操作数。然后,从操作符栈 op_stack 中弹出栈顶的操作符,并将其存储在变量 op 中。接下来,调用 apply_operator(a, b, op) 函数,对操作数 a 和 b 应用操作符 op 进行计算,并将结果压入操作数栈 num_stack 中。完成内层循环后,将当前操作符 expression[i] 压入操作符栈 op_stack 中。总之,这段代码的作用是处理表达式中的操作符。它会从操作数栈中弹出两个操作数和一个操作符,并进行相应的计算,然后将计算结果压入操作数栈中。这个过程会不断重复,直到所有的操作符都被处理完毕。*/else if (is_operator(expression[i])) {while (!op_stack.empty() && precedence(op_stack.top()) >= precedence(expression[i])) {double b = num_stack.top();num_stack.pop();double a = num_stack.top();num_stack.pop();char op = op_stack.top();op_stack.pop();num_stack.push(apply_operator(a, b, op));}op_stack.push(expression[i]);}//这段代码处理括号的情况。//首先,通过比较 expression[i] 是否等于左括号 '(' 来判断当前字符是否为左括号。//如果是左括号,则将其压入操作符栈 op_stack 中。//接下来,通过比较 expression[i] 是否等于右括号 ')' 来判断当前字符是否为右括号。//如果是右括号,则进入一个循环。循环的条件是操作符栈 op_stack 不为空,并且栈顶的操作符不是左括号 '('。//在循环中,首先从操作数栈 num_stack 中弹出栈顶的两个双精度浮点数,分别存储在变量 b 和 a 中。//然后,从操作符栈 op_stack 中弹出栈顶的操作符,并将其存储在变量 op 中。//接下来,调用 apply_operator(a, b, op) 函数,对操作数 a 和 b 应用操作符 op 进行计算,并将结果压入操作数栈 num_stack 中。//完成内层循环后,如果操作符栈 op_stack 为空,或者栈顶的操作符不是左括号 '(',则抛出运行时错误 "Mismatched parentheses",表示括号不匹配。//最后,如果操作符栈 op_stack 的栈顶操作符是左括号 '(',则将其弹出。//总之,这段代码的作用是处理括号。当遇到左括号时,将其压入操作符栈中;当遇到右括号时,将操作符栈中的操作符逐个弹出并进行计算,直到遇到左括号为止。//如果括号不匹配,则抛出运行时错误。如果所有的操作符都处理完毕后,操作符栈应该为空。如果不为空,则表示括号不匹配。最后,将左括号从操作符栈中弹出。else if (expression[i] == '(') {op_stack.push(expression[i]);}else if (expression[i] == ')') {while (!op_stack.empty() && op_stack.top() != '(') {double b = num_stack.top();num_stack.pop();double a = num_stack.top();num_stack.pop();char op = op_stack.top();op_stack.pop();num_stack.push(apply_operator(a, b, op));}if (op_stack.empty() || op_stack.top() != '(') {throw runtime_error("Mismatched parentheses");}op_stack.pop();}else {throw runtime_error("Invalid character");}}//这个循环处理剩余的运算符,直到运算符栈为空。对于每个运算符,从数字栈中弹出两个操作数,然后应用运算符并将结果压入数字栈。while (!op_stack.empty()) {double b = num_stack.top();num_stack.pop();double a = num_stack.top();num_stack.pop();char op = op_stack.top();op_stack.pop();num_stack.push(apply_operator(a, b, op));}//最后,检查数字栈中是否只剩下一个元素。如果不是,则说明表达式无效,抛出运行时错误。否则,返回数字栈中的唯一元素作为计算结果。if (num_stack.size() != 1) {throw runtime_error("Invalid expression");}return num_stack.top();
}//在主函数中,首先提示用户输入一个表达式。然后调用evaluate_expression函数计算表达式的结果,并将结果输出。
//如果在计算过程中发生错误,则捕获并输出错误信息。最后返回0表示程序成功结束。
int main() {string expression;cout << "Enter an expression: ";//getline()函数是C++标准库中的一个字符串输入函数,用于从输入流中读取一行文本并存储到字符串对象中。//使用getline()函数可以方便地读取包含空格和其他特殊字符的文本行,它会一直读取输入流直到遇到换行符或文件结束符。getline(cin, expression);//程序会提示用户输入一行文本,然后使用getline()函数读取输入的文本并存储到expression字符串中,最后输出读取到的文本。try {double result = evaluate_expression(expression);cout << "Result: " << result << endl;}catch (const runtime_error& e) {// // 处理异常的代码块cerr << "Error: " << e.what() << endl;}return 0;
}

希望对你有帮助!加油各位!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/593969.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS 中间位置翻转动画

<template><div class"container" mouseenter"startAnimation" mouseleave"stopAnimation"><!-- 旋方块 --><div class"box" :class"{ rotate-hor-center: isAnimating }"><!-- 元素内容 -->…

msvcp140.dll丢失的错误解决办法,msvcp140.dll丢失的原因

如果你的电脑中正处于msvcp140.dll丢失或找不到msvcp140.dll的问题&#xff0c;那么可以尝试使用下面的方法进行解决msvcp140.dll丢失的问题。其实msvcp140.dll文件丢失的问题解决办法也很简单&#xff0c;但是出现msvcp140.dll丢失的问题却可能是有很多原因。接下来就给大家分…

约束满足问题简介

约束满足问题的定义 约束满足问题&#xff08;Constraint Satisfying Problem, CSP&#xff09; – 由一个变量集合和一个约束集合定义&#xff1b; – 每个变量都有一个非空可能值域&#xff1b; – 每个约束指定了包含若干变量的一个子集内各变量的赋值范围。 例如&…

互联网加竞赛 Yolov安全帽佩戴检测 危险区域进入检测 - 深度学习 opencv

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; Yolov安全帽佩戴检测 危险区域进入检测 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&am…

打造专业开发者指南:针对ShardingProxy分库分表解决策略的深度剖析 – 详解部署、使用、服务治理与优化技巧

一、 ShardingProxy快速使用 ShardingProxy的功能同样是分库分表&#xff0c;但是他是一个独立部署的服务端&#xff0c;提供 统一的数据库代理服务。注意&#xff0c;ShardingProxy目前只支持MySQL和PostgreSQL。并且&#xff0c;客户端连接ShardingProxy时&#xff0c;最好使…

多模态大模型Vary:扩充视觉Vocabulary,实现更细粒度的视觉感知

前言 现代大型视觉语言模型(LVLMs)具有相同的视觉词汇- CLIP&#xff0c;它可以涵盖大多数常见的视觉任务。然而&#xff0c;对于一些需要密集和细粒度视觉感知的特殊视觉任务&#xff0c;例如文档级OCR或图表理解&#xff0c;特别是在非英语场景下&#xff0c;clip风格的词汇…

Springboot集成RabbitMq二

接上一篇&#xff1a;Springboot集成RabbitMq一-CSDN博客 1、搭建项目-消费者 与之前一样 2、创建配置类 package com.wym.rabbitmqconsumer.utils;import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.spring…

JDK17 - 开发者视角,从 JDK8 ~ JDK17 都增加了哪些新特性

目录 前言 一、站在开发视角&#xff0c;从 JDK8 升级到 JDK17 都有哪些新特性 1.1、JDK8 新特性 1.1.1、Optional 类 a&#xff09;简介 b&#xff09;使用方法 c&#xff09;使用场景 1.2、JDK9 新特性 1.2.1、Optional - ifPresentOrElse 解决 if-else 1.2.2、Opt…

Java程序设计阶段测试1

一、单选题&#xff08;共15题&#xff1b; 共30.0分&#xff09; 2.0分 1、以下哪个是Java应用程序main方法的有效定义? A.public static void main(); B.public static void main( String args ); C.public static void main( String args[] ); D.public static boolea…

Go Lang Fiber介绍

利用GoLang Fiber进行高性能Web开发 在不断发展的Web开发世界中&#xff0c;选择合适的框架至关重要。速度、简洁性和强大的功能集是每个开发者都追求的品质。在使用Go构建Web应用时&#xff0c;“Fiber”作为一个强大且轻量级的框架在众多选择中脱颖而出。在这份全面的指南中…

扩展:键盘录入笔记(next()、nextLine()、nextInt()、nextDouble())

文章目录 一&#xff0c;键盘录入涉及到的方法如下&#xff1a;1&#xff09;next&#xff08;&#xff09;、nextLine&#xff08;&#xff09;&#xff1a;代码示例&#xff1a;代码示例&#xff1a; 2&#xff09;nextInt&#xff08;&#xff09;&#xff1a;代码示例&…

无辅源电压继电器 RWY-D2/3 180-440VAC 导轨安装 josef约瑟

RWY-D1型电压继电器&#xff1b; RWY-D2型电压继电器&#xff1b; 一、 概述 RWY-D系列电压继电器&#xff08;以下简称本继电器&#xff09;用于发电机、变压器和输电线的电器保护装置中&#xff0c;作为过电压保护或低电压闭锁的启动原件。本继电器为集成电路静态型继电器…

设计模式--适配器模式

适配器模式 适配器模式&#xff08;Adapter&#xff09;&#xff0c;将一个类的接口转换为客户希望的另一个接口&#xff0c;Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 系统的数据和行为都正确&#xff0c;但接口不符合时&#xff0c;我们应该…

Python入门学习篇(十七)——封装、继承、多态

1 封装 1.1 理解 属性和方法书写到类里面的操作即为封装 封装可以理解成私有化属性和私有化方法1.2 示例代码 class Person():p_num 0 # 用于统计数量def __init__(self, name, age, sex, job):# __name为私有化属性self.__name nameself.age ageself.sex sexself.job …

使用anaconda创建爬虫spyder工程

1.由于每个工程使用的环境都可能不一样&#xff0c;因此一个好的习惯就是不同的工程都创建属于自己的环境&#xff0c;在anaconda中默认的环境是base&#xff0c;我们现在来创建一个名为spyder的环境&#xff0c;专门用于爬虫工程&#xff1a; //括号中名字&#xff0c;代表当…

森林火灾数据集

野外火灾是全球范围内最致命和危险的天然灾害之一。它不仅对人类的生命安全构成严重威胁&#xff0c;还对动植物的生存环境造成巨大的破坏。预测火灾行为不仅可以帮助消防员更好地应对火情&#xff0c;还可以为未来的火灾预防和应对策略提供有力支持。 随着航空图像技术的不断…

Windows可以ping通ubuntu,但ubuntu无法ping通windows

使用了NAT网卡和桥接网卡&#xff0c;电脑连了WiFi&#xff0c;桥接网卡桥接到WLAN上&#xff0c;Windows可以ping通Ubuntu但反过来不行&#xff01; 1.可能是防火墙的问题&#xff0c;按照如下设置&#xff0c;无果 考虑是不是使用了两个网卡冲突了&#xff0c;取消NAT的链接 …

【笔记】书生·浦语大模型实战营——第一课

群公告 1月3日*更新 第一次课程视频链接&#xff1a;https://www.bilibili.com/video/BV1Rc411b7ns/&#xff0c;第一次课程只需要记笔记&#xff0c;没有作业。第一次课程(1月3日)和第二次课程(1月5日)到本周末(1月7日)截止&#xff0c;笔记记录在 知乎/CSDN/Github 或者任何你…

【操作系统xv6】学习记录--实验1 Lab: Xv6 and Unix utilities--未完

ref:https://pdos.csail.mit.edu/6.828/2020/xv6.html 实验&#xff1a;Lab: Xv6 and Unix utilities 环境搭建 实验环境搭建&#xff1a;https://blog.csdn.net/qq_45512097/article/details/126741793 搭建了1天&#xff0c;大家自求多福吧&#xff0c;哎。~搞环境真是折磨…

QProgressDialog用法及结合QThread用法,四种线程使用

1 QProgressDialog概述 QProgressDialog类提供耗时操作的进度条。 进度对话框用于向用户指示操作将花费多长时间&#xff0c;并演示应用程序没有冻结。此外&#xff0c;QPorgressDialog还可以给用户一个中止操作的机会。 进度对话框的一个常见问题是很难知道何时使用它们;操作…