表达式求值问题的实现

news2024/12/23 5:02:29

         这是C++算法基础-数据结构专栏的第二十二篇文章,专栏详情请见此处


引入

        相信大家都会做如1+(2+3)*4/5-6这样的算式,而我们今天要学习让计算机通过表达式求它的值,这就是表达式求值问题。

        下面我们就来讲表达式求值问题的实现。

定义

        表达式求值问题要解决的问题一般是输入一个字符串表示的表达式,要求输出它的值。表达式包含两类字符:运算数和运算符。

前置过程

        在本文的学习中,你可能会在一些小节中有不懂的地方,遇到这种情况时,你应该将整篇文章阅读完,理解整体思路,再回来再看不懂的地方,此时你一定会豁然开朗(*^▽^*)

        使用数据结构:栈

        在运算的时候,需要考虑运算符优先级问题,若优先级低的数据在优先级高的数据前面,先要算完优先级高的数据再倒序回来算优先级低的数据,所以选择了这个数据结构。还有就是表达式中有运算符和数字两个对象,所以要用两个栈来存储。

        代码如下:

stack<int>num;
stack<char>op;

        在对字符串遍历之前,我们还要再干两件事。

        哈希表判断优先级

        第一就是建立一个哈希表进行映射来判断运算优先级

        代码如下:

unordered_map<char,int>pr{{'+',1},{'-',1},{'*',2},{'/',2}};
        计算函数

        第二是一个计算函数,先从数字栈取出(取出实际上是两个操作:取(取栈顶值)和出(弹出数据))两个数,符号栈中取出一个符号,再根据符号进行计算。此处有一点需要注意,由于栈先进后出的特性,先进去的数字a在后进去的数字b下面,所以先取出的应该是后进去的数字b,再取出的才是先进去的数字a。当计算完成后,还要把计算的结果向栈顶插入,以便进行下次的计算。

        代码如下:

void eval(){
	int b=num.top();
    num.pop();
	int a=num.top();
    num.pop();
	char c=op.top();
    op.pop();
	int x;
	if(c=='+') 
        x=a+b;
	else if(c=='-') 
        x=a-b;
	else if(c=='*') 
        x=a*b;
	else
        x=a/b;
	num.push(x);
}

主体过程

        今天所学的表达式求值中,表达式的运算符仅包含+,-,*,/(加 减 乘 整除(整除是向0取整)),可能包含括号,保证给定的表达式合法,所有数字均为正整数。

        围绕上述表达式的性质,我们可以看出,表达式中无非就是四种可能的情况:数字,左括号,右括号,加减乘除四种运算符号。所以,我们在进行对字符串的遍历时,分情况去考虑

        数字

        数字并不会产生运算过程,只需提取数字,将数字插入数字栈

Q:提取数字的方法是什么呢?

A:一次性提取完。具体来说,为了不对变量i造成影响,我们用一个新的变量j进行遍历;在循环中,若j在字符串里(防止该数字是字符串中最后一个数字而造成死循环)且当前字符是数字,就将当前正在处理的数据x10并加上str[j]-'0',意思就是将x的所有数位向左移动一位,再将个位赋值为str[j]用ASCII码进行偏移操作后的量(就是将此字符减去‘0’),把j++,就这样不断循环,直到数字提取完成;最后,i赋值为j-1,因为每轮循环有i++,所以我们需要倒指向最后一个数字。

注:isdigit()是一个库函数,在头文件<cctype>中,作用是判断某一字符是否为数字字符。

        代码如下:

if(isdigit(c)){
	int x=0,j=i;
	while(j<str.size()&&isdigit(str[j]))
        x=x*10+str[j++]-'0';
	i=j-1;
	num.push(x);
}
        左括号

        遇到左括号说明会往下走,所以只需将左括号插入符号栈

        代码如下:

else if(c=='(')
    op.push(c);
        右括号

        遇到右括号说明会往上走,所以要逆向运算直至遇到左括号

        代码如下:

else if(c==')'){
	while(op.top()!='(')
        eval();
	op.pop();
}
        运算符号

        遇到运算符号不意味着立即运算,而是标志着将之前入栈的算式进行运算,具体来说,前一个运算符和当前的运算符无非就是三种关系:

  1. 前一个运算符比当前的运算符的优先级要高;
  2. 前一个运算符比当前的运算符的优先级要低;
  3. 前一个运算符和当前的运算符的优先级相等。

        由于先算优先级高的运算,所以关系1可以往前运算;又由于同级运算从左向右算,所以关系3也可以往前运算;只有关系2不可以往前运算,所以说,若符号栈不为空,只要前一个运算符的优先级大于等于当前的运算符的优先级,就可以往前运算。最后,将当前的运算符插入符号栈

        代码如下:

else{
	while(op.size()&&pr[op.top()]>=pr[c])
        eval();
	op.push(c);
}
        运算剩余算式

        最后,如果若符号栈不为空,就循环运算,直到数字栈内只有一个数字,将它输出

代码

        下面给出表达式求值问题的实现代码:

stack<int>num;
stack<char>op;
void eval(){
	int b=num.top();
    num.pop();
	int a=num.top();
    num.pop();
	char c=op.top();
    op.pop();
	int x;
	if(c=='+')
        x=a+b;
	else if(c=='-')
        x=a-b;
	else if(c=='*')
        x=a*b;
	else
        x=a/b;
	num.push(x);
}
int main(){
	unordered_map<char,int>pr{{'+',1},{'-',1},{'*',2},{'/',2}};
	string str;
	cin>>str;
	for(int i=0;i<str.size();i++){
		char c=str[i];
		if(isdigit(c)){
			int x=0,j=i;
			while(j<str.size()&&isdigit(str[j]))
                x=x*10+str[j++]-'0';
			i=j-1;
			num.push(x);
		}
		else if(c=='(')
            op.push(c);
		else if(c==')'){
			while(op.top()!='(')
                eval();
			op.pop();
		}
		else{
			while(op.size()&&pr[op.top()]>=pr[c])
                eval();
			op.push(c);
		}
	}
	while(op.size())
        eval();
	cout<<num.top();
	return 0;
}

上一篇-栈的实现    C++算法基础专栏文章    下一篇-队列的实现


每周六更新一篇文章,内容一般是自己总结的经验或是在其他网站上整理的优质内容

点个赞,关注一下呗~

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

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

相关文章

mysql的聚簇索引、非聚簇索引、回表

1.聚簇索引和非聚簇索引 聚簇索引&#xff08;聚集索引&#xff09;&#xff1a;数据和索引放在一起&#xff0c;B树的叶子节点存放了整行数据&#xff0c;有且只有一个。 【主键索引和唯一索引&#xff0c;主键唯一&#xff0c;存放的是主键对应的整行数据】非聚簇索引&#…

[CR]厚云填补_Diffusion Enhancement for CR

Diffusion Enhancement for Cloud Removal in Ultra-Resolution Remote Sensing Imagery Abstract 云层的存在严重影响了光学遥感图像的质量和有效性。然而&#xff0c;现有的基于深度学习(DL)的云移除(CR)技术&#xff0c;通常以保真度驱动的损失作为约束&#xff0c;例如L1或…

USB3.2 摘录(11)

系列文章目录 USB3.2 摘录&#xff08;一&#xff09; USB3.2 摘录&#xff08;二&#xff09; USB3.2 摘录&#xff08;三&#xff09; USB3.2 摘录&#xff08;四&#xff09; USB3.2 摘录&#xff08;五&#xff09; USB3.2 摘录&#xff08;六&#xff09; USB3.2 摘录&…

OpenAI神秘“草莓”项目 计划最早今年秋季推出

据科技媒体The Information报道&#xff0c;OpenAI神秘“草莓”项目&#xff0c;计划最早今年秋季推出&#xff01;上个月&#xff0c;OpenAI的内部团队被曝出正开发的“草莓”&#xff08;Strawberry&#xff09;项目&#xff0c;目的是增强OpenAI的模型的推理能力&#xff0c…

大模型从入门到精通—— LLM 应用评估(一)

如何评估 LLM 应用 1. 简介 在使用大型语言模型&#xff08;LLM&#xff09;构建应用程序时&#xff0c;评估的思路往往与传统的 AI 开发有所不同。传统 AI 的评估可能依赖于大规模的标注数据集和精细的性能指标&#xff0c;而 LLM 的开发则更注重迭代验证&#xff0c;并在开发…

python从入门到精通:异常操作、模块操作及包操作

目录 1、异常概念 2、异常的捕获方法 3、异常的传递 4、python模块 4.1、模块的导入 4.2、自定义模块 5、python包 5.1、自定义python包 5.2、安装第三方包 1、异常概念 当检测到一个错误时&#xff0c;python解释器会无法执行&#xff0c;反而出现一些错误的提示&a…

视频中间件:大华视频设备接入管理应用

前言 上篇博文介绍了视频中间件&#xff1a;海康视频设备的接入管理&#xff1f;&#xff0c;今天给大家带来大华视频设备的接入管理&#xff0c;视频中间件平台支持大华Sdk、大华主动注册、Onvif、Rtsp、Gb28181等方式对大华视频设备的接入管理。同时视频中间件可支持协议互转…

离子交换技术在含银废水处理中的创新应用

随着科技的不断进步&#xff0c;金属制品在各行各业中扮演着越来越重要的角色。其中&#xff0c;镀银工艺作为一种提高金属制品性能的重要手段&#xff0c;其环境影响也日益受到关注。镀银过程中产生的含银废水含有多种有害物质&#xff0c;对环境构成潜在风险。因此&#xff0…

百度:未来or现在 顾此失彼?

用AI押注未来&#xff0c;却丢了现在 国内AI先行者百度 走到哪了&#xff1f; 作为这个星球最热门的概念&#xff0c;AI无疑是个好故事&#xff0c;不只是百度&#xff0c;美股的一众科技公司几乎都在讲述自己的AI投入及发展成果&#xff0c;市值也随着AI预期坐过山车。而市场…

Datawhale AI夏令营第五期CV方向-城市管理违规行为智能识别-Task1

赛题解析 城市管理违规行为智能识别 初赛任务是根据给定的城管视频监控数据集&#xff0c;进行城市违规行为的检测。违规行为主要包括垃圾桶满溢、机动车违停、非机动车违停等。 选手需要能够从视频中分析并标记出违规行为&#xff0c;提供违规行为发生的时间和位置信息。 数…

ArkTS--状态管理

一、概述 在声明式UI编程范式中&#xff0c;UI是应用程序状态的函数&#xff0c;应用程序状态的修改会更新相应的UI界面。ArkUI采用了MVVM模式&#xff0c;其中ViewModel将数据与视图绑定在一起&#xff0c;更新数据的时候直接更新视图。如下图所示&#xff1a; ArkUI提供了一系…

Day49 | 53. 寻宝 prim算法 与kruskal算法

语言 Java 53. 寻宝 53. 寻宝&#xff08;第七期模拟笔试&#xff09; 题目 题目描述 在世界的某个区域&#xff0c;有一些分散的神秘岛屿&#xff0c;每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路&#xff0c;方便运输。 不同岛屿之间&#xff0c…

【MATLAB学习笔记】绘图——自定义标记(Marker)形状,实现与MATLAB自带标记基本一致的功能(自适应缩放、自适应裁剪)

目录 前言自定义标记函数自定义标记函数的说明纵横比调整将图形大小按磅数设置平移标记点绘制标记点边界标记点不裁剪 拓展功能——标记点自适应绘图区的缩放绘图区缩放回调函数标记点大小自适应标记点裁剪自适应 示例基本绘图自定义标记函数的使用 总代码主函数自定义标记函数…

RKNPU2从入门到实践 --- 【4】RKNN 模型构建【使用pycharm一步一步搭建RKNN模型】

目录 前言 1.1 RKNN 初始化及对象释放 1.1.1 概念介绍 1.1.2 实际演示 1.2 RKNN 模型配置 1.2.1 概念介绍 1.2.2 实际演示 1.3 模型加载 1.3.1 概念介绍 1.3.1.1 Caffe模型加载接口 1.3.1.2 TensorFlow模型加载接口 1.3.1.3 TensorFlowLite 模型加载接口 1.3.…

debian12 - 修改SSH端口连接回包

文章目录 debian12 - 修改SSH端口连接回包概述笔记先猜猜回包是哪个程序回的去下载对应版本的openssh代码工程用telnet测试的效果todo 关于ssh状态为active(start)的原因END debian12 - 修改SSH端口连接回包 概述 和同学讨论问题。 他说&#xff0c;用telnet去连接SSH端口&am…

数据仓库系列10:如何处理维度表中的变化类型?

想象一下,你正在管理一个电商平台的数据仓库。突然,你发现一个重要客户的地址发生了变化。这个简单的变更可能会对你的分析产生巨大影响。如何确保你的数据仓库能够准确地反映这种变化,同时又不丢失历史信息?欢迎来到数据仓库中最具挑战性的问题之一:维度表变化的处理。 目录…

记录imbalanced_learn离线安装

1 离线安装需要3个文件&#xff1a; 文件位置&#xff1a; ‘D:\非常重要\imbalanced-learn’ 2 复制到这个路径&#xff0c;即可 ‘…/miniconda3/lib/python3.8/site-packages’

数据结构与算法——Java实现 1.初识算法 —— 二分查找

目录 一、线性查找 二、二分查找 基础版 问题1 —— 循环条件 问题2 —— ij/2有没有问题 问题3 —— 代码中都写成 < 有何好处 改动版 人生的意义就是要独自穿过悲喜 —— 24.8.27 需求:在有序数组A内&#xff0c;查找值 target&#xff0c;如果找到返回索引&#xff0c;如…

小鹏在这次发布会上有哪些黑科技呢?

在今晚举办的小鹏10年热爱之夜&小鹏MONA MO3上市发布会上&#xff0c;何小鹏宣布&#xff0c;小鹏自研图灵芯片已于8月23日流片成功。据介绍&#xff0c;小鹏图灵芯片是全球首颗同时应用在AI汽车、机器人、飞行汽车的AI芯片&#xff0c;为AI大模型定制。 该芯片采用40核心…

【STM32】时钟体系

一、时钟体系 为什么需要时钟&#xff1f; 时钟可以为系统提供精确的定时&#xff0c;比如时间显示&#xff0c;定时器&#xff0c;pwm… 为芯片各功能模块提供工作势能,使能各组管脚工作&#xff0c;如果不使能&#xff0c;管脚无法工作 同步数据传输 给单片机提供一个时…