首页 > 编程语言 >C++ 中缀表达式判断合法性并求值

C++ 中缀表达式判断合法性并求值

时间:2024-07-28 23:06:11浏览次数:13  
标签:优先级 中缀 int 栈顶 C++ 运算符 求值 表达式 op

中缀表达式值


题目描述

输入一个中缀表达式(由 0−9 组成的运算数、加 + 减 − 乘 ∗ 除 / 四种运算符、左右小括号组成。注意“−”也可作为负数的标志,表达式以“@”作为结束符)。

判断表达式是否合法,如果不合法,请输出“NO”;
否则请把表达式转换成后缀形式,再求出后缀表达式的值并输出。
注意:必须用栈操作,不能直接输出表达式的值。

输入描述

一行为一个以 @ 结束的字符串。

输出描述

如果表达式不合法,请输出“NO”,要求大写。

如果表达式合法,请输出计算结果。

输入样例:

1+2*8-9@

输出样例

8

简化:[NOIP2013 普及组] 表达式求值


解析

\(\mathbf{O}\) 输入字符串

\(\mathbf{I}\) 检查与预处理

  (1)检查 @ 并删除其及其后所有内容

  (2)检查括号匹配
    a. 对于每一位置,其左侧 ( 数量必须大于等于 ) 数量
    b. ( 总数必须等于 ) 总数

  (3)预处理负号(负号前加 0
    a. 字符串开头 -... 改为 0-...
    b. 字符串中间 ...(-...)... 改为 ...(0-...)...

  (4)检查运算符合法性
    a. 字符串内不能有非法符号(即非 1234567890 +-*/ () 的符号)
    b. 运算符(+-*/)两侧必须为数字或括号

\(\mathbf{II}\) 中缀表达式转为后缀表达式

  (1)遇到数字直接输出(指加入后缀表达式,下同)

  (2)遇到运算符
    a. 如果栈为空,直接入栈
    b. ( 直接入栈
    c. 遇到 ),弹栈并输出直至遇到 (
    d. 优先级高于栈顶的运算符:直接入栈
    e. 优先级小于等于栈顶的运算符:弹栈并输出至其优先级高于栈顶,而后入栈

\(\mathbf{III}\) 计算后缀表达式的值

  (1)读取到符号:取出栈顶的两个元素运算后入栈

  (2)读取到数字:直接入栈

\(\mathbf{IV}\) 输出栈顶元素

其他细节见代码及注释


代码

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;

const int N=1e5+5;
string st;
pair<bool,int> pf[N]; //<type(0-num,1-op),number/op>
int pftop=0;
stack<char> op; //<operator>

inline int type(char ch)
{
	if(ch>='0'&&ch<='9') return 0;
	if(ch=='+'||ch=='-'||ch=='*'||ch=='/') return 1;
	if(ch=='('||ch==')') return 2;
	return -1;
}
inline int priority(char op)
{
	if(op=='+'||op=='-') return 0;
	if(op=='*'||op=='/') return 1;
	return -1;
}
bool Check_and_Preprocessing()	//1、检查是否合法,并预处理 
{
	bool FlagOfAt=false;
	for(int i=0;i<st.length();i++) //(1)检查是否有'@'并删除其及以后所有内容 
		if(st[i]=='@')
		{
			st.erase(i);
			FlagOfAt=true;
			break;
		}
	if(!FlagOfAt) return false;
	
	int LeftBracketsCount=0;
	for(int i=0;i<st.length();i++) //(2)检查括号是否匹配
	{
		if(st[i]=='(') LeftBracketsCount++;
		if(st[i]==')') LeftBracketsCount--;
		if(LeftBracketsCount<0) return false;
	}
	if(LeftBracketsCount) return false; 
	
	string tmpst;
	for(int i=0;i<st.length();i++) //(3)预处理负号
	{
		if(st[i]=='-')
		{
			if(!i) tmpst+='0'; //a. -...
			else if(st[i-1]=='(') tmpst+='0'; //b. ...(-x)...
		}
		tmpst+=st[i];
	}
	st=tmpst;
	
	if(type(st[0])==1||st[st.length()-1]==1 || type(st[0])==-1) return false; //(4)检查运算符是否合法 
	for(int i=1;i<st.length();i++)
	{
		if(type(st[i])==-1) return false; //a.出现非法符号 
		if(type(st[i])==1) //b.运算符两侧不为数或括号 
		{
			if(type(st[i-1])==1||type(st[i+1])==1) return false; //b i.+*
			if(st[i-1]=='('||st[i+1]==')') return false; //b ii.(+)
		}
	}
	
	return true; //(5)你过关! 
}

void PostfixExpression() //2、先将中缀表达式转换为后缀表达式
{
	for(int i=0;i<st.length();i++) //(1)依次扫描中缀表达式
	{
		if(!type(st[i])) //(2)遇到数字输出到后缀表达式
		{
			int x=0;
			while(st[i]>='0'&&st[i]<='9')
			{
				x=(x<<3)+(x<<1)+(st[i]^48);
				i++;
			}
			pf[++pftop]=make_pair(0,x);
			i--;
		}
		else //(3)遇到运算符,有以下几种情况
		{
			if(op.empty()||st[i]=='(') op.push(st[i]); //a:栈空直接入栈;b:遇到’(‘直接入栈
			else if(st[i]==')') //c:遇到’)‘一直出栈并输出,直到’(‘出栈为止,但’('不作为输出(因为后缀表达式中没有括号)
			{
				while(op.top()!='(')
				{
					pf[++pftop]=make_pair(1,op.top());
					op.pop();
				}
				op.pop();
			}
			else
			{
				if(priority(st[i])>priority(op.top())) //d:遇到运算符优先级高于栈顶运算符优先级,则入栈
					op.push(st[i]);
				else //e:遇到运算符优先级低于或等于栈顶运算符优先级,则出栈,直到其优先级高于栈顶运算符优先级时停止或栈为空),最后再将其入栈
				{
					while(!op.empty() && priority(st[i])<=priority(op.top()))
					{
						pf[++pftop]=make_pair(1,op.top());
						op.pop();
					}
					op.push(st[i]);
				}
			}
		}
	}
	while(!op.empty())
	{
		pf[++pftop]=make_pair(1,op.top());
		op.pop();
	}
	return;
}

stack<int> calc;
inline int calc_op(char op,int x,int y)
{
	if(op=='+') return x+y;
	if(op=='-') return x-y;
	if(op=='*') return x*y;
	if(op=='/') return x/y;
	return 0;
}
inline int Calculate() //3、计算后缀表达式的值 
{
	for(int i=1;i<=pftop;i++)
	{
		if(pf[i].first) //(1)读取到符号 
		{
			int t1=calc.top();calc.pop();
			int t2=calc.top();calc.pop();
			calc.push(calc_op(pf[i].second,t2,t1));
		}
		else calc.push(pf[i].second); //(2)读取到数字 
	}
	return calc.top();
}
int main()
{
	getline(cin,st);
	if(!Check_and_Preprocessing())
	{
		printf("NO\n");
		return 0;
	}
	PostfixExpression();
	int ans=Calculate();
	printf("%d\n",ans);
	return 0;
}

标签:优先级,中缀,int,栈顶,C++,运算符,求值,表达式,op
From: https://www.cnblogs.com/jerrycyx/p/18329124

相关文章

  • VS2022创建C C++ GTEST工程
    原因需要对带代码进行单元测试,选择在Visualstudio中使用GTEST框架。实施创建一个常规的控制台可执行程序。然后使用NUGET安装包安装GTEST头文件和动态库,同时安装GTESTADAPTER。安装可能提示找不到包源,此时需要根据提示配置一下,注意通配符很关键,不要问为甚吗,就是有bug......
  • C++ 笔记(一)数据类型(1)
    1简单的变量变量名命名规则如下变量名称可以包含字母、数字和下划线(_)。变量名称的第一个字符必须是字母或下划线。区分大小写,即大写字母和小写字母被认为是不同的字符。不能使用C++的关键字作为变量名。2数据类型2.1整型short、int、long和longlong这四种类型都是......
  • C++关键字——inline和auto
    目录一、前言 二、inline关键字(C++11)---多用于内联函数a.概念b.特性三、auto关键字(C++11)a.auto简介b.auto的使用细则c.auto不能推导的场景d.基于范围的for循环(C++11)一、前言C++总计63个关键字,我们先了解inline和auto这两个关键字。asmdoifreturntrycontinue......
  • 三种语言实现高精度加法(C++/Python/Java)
    题目给定两个正整数(不含前导00),计算它们的和。1≤整数长度≤100000C++#include<bits/stdc++.h>usingnamespacestd;vector<int>add(vector<int>&A,vector<int>&B){if(A.size()<B.size())returnadd(B,A);vector<int>C;......
  • 互联网大裁员背景下C++程序员该如何突围?
    一、前言              近期遇到许多正在找工作的小伙伴感叹今年工作难找,往年互联网上升期的时候,北京互联网行业不光工资给的高,而且坑也多,就拿互联网前几大语言来说,20年北京区Java招聘岗位10万+,目前只有不到1万+,20年北京区python招聘岗位3万+,2024年4月份不到5......
  • C++从入门到起飞之——内存管理(万字详解) 全方位剖析!
    ......
  • 浅谈简单的数据结构1(树状数组 、线段树)(c++)
    *_*课间休息后的知识点轰炸树状数组引入给定长为n的序列a,q次操作,每次查询一段区间的和,或修改一个数的权值。1≤n,q≤5×10^5,0≤a_i≤10^9。分析如果没有修改操作,这是一道非常简单的前缀和题。假如我们修改前缀和数组,查询就还是O(1)的,是否可行呢?当然不行。考虑......
  • 浅谈图论中树及其相关知识点(树的遍历、直径、最近公共祖先)(c++)
    目录前言一.关于树二.树的遍历(一)遍历方式常见遍历1.DFS遍历2.BFS遍历二叉树遍历1.先序遍历2.中序遍历3.后序遍历(二)例题讲解1.P1030[NOIP2001普及组]求先序排列思路AC代码 2.P5908猫猫和企鹅思路AC代码  3.P1395会议思路AC代码三.树的直径(一)定......
  • 三种语言实现浮点数二分(C++/Python/Java)
    题目给定一个浮点数......
  • C++ 多态
    多态基本概念多态是C++面向对象三大特性之一多态分为两类静态多态:函数重载和运算符重载属于静态多态,复用函数名动态多态:派生类和虚函数实现运行时多态静态多态和动态多态区别:静态多态的函数地址早绑定——编译阶段确定函数地址动态多态的函数地址晚绑定——运行阶段确......