表达式求值问题-双栈模板化实现

news2024/9/23 23:33:15

        好久不见,真的很久都没有更新博客了,最近很多事情,所以比较忙碌,没有时间每天都学算法,但是我会挤时间尽量做到,每两三天就更新博客,我会努力的,加油~

    前言:计算器都见过吧,我们今天要讲的就是类似于计算器计算数据的简单实现,我们需要注意一些问题,比如运算符优先级,运算顺序等等问题,话不多说,冲冲冲!!!

目录

1.问题引入

2.问题分析及解决方法

如何设计优先级问题?

设计计算函数和启动计算条件

完整代码(可做为表达式计算模板使用)

3.金句频道


1.问题引入

2.问题分析及解决方法

       首先,我们先来看一下整体思路:对于一个表达式,我们会读入括号,运算符和数字三种字符,我们需要将这些字符区分开再进行计算,为了保证运算的正确性,由运算符带来的优先级问题是我们解决这个问题的关键,解决了运算符优先级问题,我们就可以将运算符和数字分别存入一个栈中,用读取到' ) '和读取到优先级比已经保存在栈内的运算符来作为启动计算的条件(读到右括号,我们就可以将整个括号内部的部分算出来,再将算得结果压入保存数字的栈中用于后续的计算,而对于读取到优先级低的运算符,因为我们以栈存储数据,导致我们在计算的时候就会按逆序进行计算,所以,我们每次读取到一个运算符优先级低于栈顶的字符,都要先将栈内的运算符优先级高的运算符的结果算出,从而不影响运算顺序),最后,我们的运算符栈内如果还剩下元素,直接计算即可。

如何设计优先级问题?

       这里方法就有很多了,既可以用一个专门的函数来实现,也可以用STL的map键值来实现等等,这里我们采用第二种方法,该方法比较简单且代码易扩展,方便后序添加运算符。

unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用来表示运算符的优先级,数字越大表示运算优先级越高

设计计算函数和启动计算条件

//计算函数
void f()
{
	//这里需要注意,我们的栈内保存的待运算数字和运算顺序是反着的,会影响减法和除法的计算
	auto b = num.top(); num.pop();
	auto a = num.top(); num.pop();
	auto c = op.top(); op.pop();
	if (c == '+')
		num.push(a + b);
	else if (c == '-')
		num.push(a - b);
	else if (c == '*')
		num.push(a * b);
	else if (c == '/')
		num.push(a / b);
	//如果想要再拓展其他运算,可在此处继续写下去

}

//计算启动条件
else if (s[i] == '(')//如果是左括号,直接入栈等待右括号到来再计算
			op.push(s[i]);
		else if (s[i] == ')')//右括号,准备开始计算结果
		{
			while (op.top() != '(') f();//做括号内的计算
			op.pop();//弹出左括号
		}
		else
		{
			while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到优先级比前面已经入栈的运算符的优先极低的,则要先解决栈内的计算再将该优先级高的字符入栈
			op.push(s[i]);
		}

完整代码(可做为表达式计算模板使用)

#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
const int maxn = 1e5 + 10;

stack<int >num;
stack<char> op;//运算符

unordered_map<char, int> p{ {'+',1},{'-',1},{'*',2},{'/',2} };//用来表示运算符的优先级,数字越大表示运算优先级越高

void f()
{
	//这里需要注意,我们的栈内保存的待运算数字和运算顺序是反着的,会影响减法和除法的计算
	auto b = num.top(); num.pop();
	auto a = num.top(); num.pop();
	auto c = op.top(); op.pop();
	if (c == '+')
		num.push(a + b);
	else if (c == '-')
		num.push(a - b);
	else if (c == '*')
		num.push(a * b);
	else if (c == '/')
		num.push(a / b);
	//如果想要再拓展其他运算,可在此处继续写下去

}
int main()
{
	string s;
	cin >> s;
	for (int i = 0; i < s.size(); i++)
	{
		if (isdigit(s[i]))//注意,这里需要注意10以上的数,不能只看一个字符就完了
		{
			int j = i;
			int temp = 0;
			while (j < s.size() && isdigit(s[j]))
			{
				temp = temp * 10 + s[j++] - '0';
			}
			i = j-1;//j在退出循环之前已经自增了,所以要减去
			num.push(temp);
		}
		else if (s[i] == '(')//如果是左括号,直接入栈等待右括号到来再计算
			op.push(s[i]);
		else if (s[i] == ')')//右括号,准备开始计算结果
		{
			while (op.top() != '(') f();//做括号内的计算
			op.pop();//弹出左括号
		}
		else
		{
			while (!op.empty() && p[op.top()] >= p[s[i]]) f();//如果遇到优先级比前面已经入栈的运算符的优先极低的,则要先解决栈内的计算再将该优先级高的字符入栈
			op.push(s[i]);
		}
	}
	//如果最后栈内还剩下字符,直接计算即可
	while (op.size()) f();
	printf("%d\n", num.top());

	return 0;
}

     我们这里将计算函数和优先级单独设计,目的就是增加代码的可复用性,main函数内部没有涉及运算符的种类和其他的特殊处理,将特异性的功能封装成函数方便后序增添功能。

3.金句频道

       常常熬不住的时候也想找个靠山靠一下,可怎么找都会发现,有的山长满荆棘,有的山上全是野兽,所以你应该是自己的那座山。过度的依赖总会失掉自我,变得被动,不要总是整天“大佬带我飞”,让自己强起来才是一芳永逸的事。要相信每一次普通的改变,都可能改变原本的普通。

 

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

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

相关文章

加码本地生活、成为“万能入口”,抖音完成了百度曾经的梦想

文|螳螂观察 作者| 小别 前有美团点评&#xff0c;后有阿里巴巴&#xff0c;本地生活服务从来就不平静。 并没有在最好的时间出发的抖音&#xff0c;还是顺着短视频的内容优势&#xff0c;从团购、本地游、外卖再到近期推出商城频道&#xff0c;逐步完善了本地生活服务的布局…

浅谈jmeter性能测试步骤入门

一、Jmeter简介 1 概述 jmeter是一个软件&#xff0c;使负载测试或业绩为导向的业务&#xff08;功能&#xff09;测试不同的协议或技术。 它是 Apache 软件基金会的Stefano Mazzocchi JMeter 最初开发的。 它主要对 Apache JServ&#xff08;现在称为如 Apache Tomca…

linux命令文本命令之~~~ sort ~~ tr ~~cut ~~ uniq

目录 一. sort命令二. uniq 命令三. tr命令四. cut命令 一. sort命令 以行为单位对文件内容进行排序&#xff0c;也将他根据不同的数据类型来排序 比较原则是从首字符向后&#xff0c;依次按ASCII码进行比较&#xff0c;最后按照升序输出排序 语法格式&#xff1a; sort 【选…

Web自动化测试:selenium的使用以及关于driver=webdriver.Firefox()无驱动报错问题

Selenium 1.什么是Selenium&#xff1f; Selenium是一个用于Web应用程序测试的工具。 主流的自动化测试工具有&#xff1a; web自动化测试&#xff1a;selenium、robot frameworkApp端自动化测试&#xff1a;Appium、Monkeyrunner、UIautomationPC客户端&#xff08;win32&…

打印机错误0x00000bc4,Win11系统找不到打印机怎么办

近期&#xff0c;又有不少小伙伴更新了Win11系统后&#xff0c;出现了打印机提示错误代码0x00000bc4&#xff0c;出现错误后&#xff0c;可能导致打印机无法正常工作&#xff0c;打印任务无法完成&#xff0c;或者打印机无法连接到电脑等问题。驱动人生就为大家带来打印机错误0…

使用docker部署wiki.js

安装docker这些就不讲了&#xff0c;教程一堆&#xff0c;相关的安装教程可以去官网看&#xff0c;只是没那么详细&#xff0c;尤其是有关数据库的配置&#xff1a;Docker 部署 Wiki.js pull wiki镜像&#xff1a; docker pull ghcr.io/requarks/wiki 如果是arm的机器&#xf…

Oracle存储过程~封神之作

简介 Oracle 存储过程是 Oracle 数据库中的一种数据处理对象&#xff0c;它可以在数据库中定义一组预定义的 SQL 语句&#xff0c;用于完成特定的数据库操作。存储过程可以被授权的用户调用&#xff0c;并且可以执行多个语句&#xff0c;这些语句可以被视为一个单独的操作&…

【逗老师的无线电】快速记录一下MMDVM串口屏相关

最近在研究MMDVM的串口屏&#xff0c;设计知识点比较多&#xff0c;本文先随手记一下&#xff0c;同时随时更新&#xff0c;最后形成完整的文档 一、Nextion和国内串口屏设计 MMDVM默认对接的是Nextion屏幕。但是有人跟我说&#xff0c;NXT的屏幕和国内陶晶驰的屏幕就是一个…

每周一算法:差分算法

差分算法 差分是一种常见的算法&#xff0c;用于快速修改数组中某一段区间的值。其基本思想就是预处理出数组的差分数组&#xff0c;然后修改区间时&#xff0c;只需要修改两个位置的值&#xff0c;即可快速完成区间修改。最后再通过差分数组求出原数组。差分算法在区间加、区…

kafka安装及配置

1. 下载 下载地址&#xff1a;Apache Kafka 我这里下载的是 3.2.1 版本。 2. 上传并解压 上传到 linux 下的 /home/software/ 目录下&#xff0c;然后解压 kafka_2.13-3.2.1.tgz 包到/usr/local/ cd /home/software tar -zxvf kafka_2.13-3.2.1.tgz -C /usr/local # -C 选…

【机器学习】信息量、香农熵、信息增益(增加例子,方便理解)

这节可以搭配 【机器学习】Logistic回归&#xff08;重新整理&#xff09;信息量&#xff08;信息&#xff09;信息量公式的推理过程 香农熵信息增益 【机器学习】Logistic回归&#xff08;重新整理&#xff09; B站视频&#xff1a;“交叉熵”如何做损失函数&#xff1f;打包…

医学影像系统源码,三维后处理和重建 PACS源码

医学影像系统源码&#xff0c;三维后处理和重建 PACS源码 医学影像系统由PACS系统、RIS系统组成&#xff0c;提供与HIS的接口&#xff08;HL7或其他类型&#xff09;。 主要功能介绍 信息预约登记 支持对患者、检查项目、申请医生、申请单据、设备等信息进行管理。且支持检查…

Apache网站部署SSL证书开启https访问,强制http跳转https

centos服务器博客网站安装教程可见&#xff1a;Centos 7.X WordPress博客网站详细教程 FTP/PHP/mysql/Apache环境构建_autotian的博客-CSDN博客本文详细的介绍了centos7.x系统下&#xff0c;如何构建FTP、mysql、PHP、Apache环境&#xff0c;并成功安装WordPress博客网站。http…

Java—JDK8新特性—函数式接口【内含思维导图】

目录 3.函数式接口 思维导图 3.1 什么是函数式接口 3.2 functionalinterface注解 源码分析 3.3 Lambda表达式和函数式接口关系 3.4 使用函数式接口 3.5 内置函数式接口 四大核的函数式接口区别 3.5.1 Supplier 函数式接口源码分析 3.5.2 Supplier 函数式接口使用 3.…

基于AT89C51单片机的篮球计时记分设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87771065 源码获取 主要内容: 基于51单片机设计篮球计时计分器,结合单片机串行接口原理,用AT89C51设计一个篮球比赛计分计时器,能够通过数码管显示分数和比赛时间(并设有…

linux驱动-gpio

最近处理es8336声卡问题&#xff0c;最后排查是spk_ctl_gpio和hp_det_gpio这两个gpio导致的&#xff0c;所以恶补了一下gpio相关的知识&#xff0c;现在总结一下。 源代码使用的是飞腾的gitee上开源的内核&#xff1a;https://gitee.com/phytium_embedded/phytium-linux-kernel…

什么是SVG格式?如何制作?

图像质量对页面非常重要——扭曲和缩放变形的标志、图标或照片会使页面看起来粗糙和不协调&#xff0c;这个问题只会因为响应设计而复杂。 访问者通过桌面机和智能手机查看应用程序&#xff0c;因此无论使用什么设备&#xff0c;图像都应该进行优化。如果有一个数字格式可以让…

基于FPGA+JESD204B 时钟双通道 6.4GSPS 高速数据采集设计(三)连续多段触发存储及传输逻辑设计

本章将完成数据速率为 80MHz 、位宽为 12bits 的 80 路并行采样数据的连续多 段触发存储。首先&#xff0c;给出数据触发存储的整体框架及功能模块划分。然后&#xff0c;简介 MIG 用户接口、设置及读写时序。最后&#xff0c;进行数据跨时钟域模块设计&#xff0c;内存…

XC7VX690T PCIE 硬件设计注意事项

首先参考PG023找到对应封装支持的位置 然后参考UG476找到对应的实际物理位置 XILINX 也有给出对应的推荐位置

gitlab服务器发送邮件配置

1.修改gitlab的配置文件&#xff1a; vim /etc/gitlab/gitlab.rb 这里具体的gitlab.rb文件所在路径需要根据实际的来 找到如下图所示的部分&#xff0c;放开注释&#xff0c;修改配置&#xff0c;此处我用的发件邮箱是QQ邮箱&#xff0c;所以域名配置都是qq.com&#xff0c;…