首页 > 其他分享 >表达式相关(一)操作数栈、运算符栈

表达式相关(一)操作数栈、运算符栈

时间:2024-08-07 11:30:25浏览次数:13  
标签:操作数 return int 栈顶 运算符 表达式 op

NOIP2013普及组T2

只有加法和乘法的表达式

思考:
使用tok来存放操作数或操作符(在编译器词法分析中称之为token,故简写为tok);输入只有一行可以用fgets,不知道题目给的输入文件有没有换行(fgets是会读入换行符的),所以还要加个判断,不然存放的时候会把换行符也当做运算符

对于2+3+...的表达式,读到2+3之后可以直接先算出5,结果是与5+...等价的;然而读到2+3...的表达式,需要先计算3...后面的内容,因为乘法的优先级比加法要高;故只读到2+3的时候不能先做计算,反之读到2*3可以先算。

每次读到操作数肯定要进栈;读到操作符,则根据优先级进行判断和计算;因此需要两个栈

一个简单的便于理解的小图示


大致推断出过程:

解析token
若为操作数则入栈
若为运算符:
若运算符栈为空,则将当前运算符入栈
若当前运算符优先级高于栈顶运算符,则将当前运算符入栈
否则不断循环,直至运算符栈为空或者当前运算符优先级高于栈顶运算符:
栈顶两个操作数出栈
栈顶运算符出栈
将两个操作数进行计算,再进栈
循环结束,将当前运算符入栈

实际写代码时考虑到判断运算符栈为空比较困难,需要一个哨兵;

大致长这样,关于括号的事情后面再写

#include<bits/stdc++.h>
using namespace std;
char tok[100000][20];
int tok_max=0;
char s[500000];

int calc(char op,int num1,int num2){
	assert(op=='+'||op=='*');
	if(op=='+')return num1+num2;
	if(op=='*')return num1*num2;
}

int priority(char op){
	if(op=='*')return 2;
	if(op=='+')return 1;
}
int main(){
	fgets(s,sizeof(s),stdin);
	int num=0;
	if(s[strlen(s)-1]=='\n'){
		s[strlen(s)-1]=0;
	}
	for(int i=0;i<strlen(s);i++){
		if(isdigit(s[i])){
			num=num*10+s[i]-'0';
		}
		else{
			++tok_max;++tok_max;
			sprintf(tok[tok_max-1],"%d",num);
			*tok[tok_max]=s[i];
			num=0;
		}
	}
	++tok_max;
	sprintf(tok[tok_max],"%d",num);
	
	//printf("tok_max..%d\n",tok_max);
	//for(int i=1;i<=tok_max;i++){
	//	puts(tok[i]);
	//}
	
	stack<int>optr,opnd;
	//运算符栈、操作数栈
	optr.push('#');//检验运算符栈非空的哨兵 
	for(int i=1;i<=tok_max;i++){
		if(isdigit(*tok[i])){
			int num1;
			sscanf(tok[i],"%d",&num1);
			opnd.push(num1);
		}
		else{
			for(;optr.top()!='#' && priority(*tok[i]) <= priority(optr.top());){
				int num2=opnd.top();opnd.pop();
				int num3=opnd.top();opnd.pop();
				char op=optr.top();optr.pop();
				opnd.push(calc(op,num3,num2)%10000);
			}
			optr.push(*tok[i]);
		}
	}
	//printf("%d\n",opnd.top());
	
	for(;optr.top()!='#';){
		int num2=opnd.top();opnd.pop();
		int num3=opnd.top();opnd.pop();
		char op=optr.top();optr.pop();
		opnd.push(calc(op,num3,num2)%10000);
	}
	printf("%d\n",opnd.top()%10000);

	return 0;
}

标签:操作数,return,int,栈顶,运算符,表达式,op
From: https://www.cnblogs.com/jisuanjizhishizatan/p/18346651

相关文章

  • 运算符
    六、运算符算术运算符一元运算符++,--二元运算符+,-,*,/,%赋值运算符=扩展运算符+=,-=,*=,/=关系运算符>,<,>=,<=,==,!=,instanceof逻辑运算符&&,||,!,^位运算符&,|,^,~,>>,<<,>>>条件运算符?:字符串连接符+1、算数运算符1、一元运算符算数运算符中++,--......
  • 位运算符
    1.与(&)2.或(|)3.亦或(^)4.非(~)5.关于位运算的面试题问:如何用电脑将2乘8最快算出?6.左移右移的底层原理......
  • 逻辑运算符
    1.与(&&)两个变量必须一致(都是true),否则否则输出的就是false2.或(||)我或者你,其中一个变量是true,那么输出的值就一定是true3.非(!())把括号里的值进行反转,比如括号是真,则输出为假......
  • 通配符和正则表达式区别
    通配符和正则表达式区别通配符是shell自带的用于匹配文件名的工具,多用在文件名上,比如查找find,ls,cp等等。正则表达式则需要特定命令的支持才可以使用,如:grep、sed和awk(号称Linux三剑客)、vi/vim、perl等,这些都是处理文本的工具。其次,shell对通配符与正则表达式的处理也有不同,“......
  • ABAP 宿主表达式(Host Expressions)
    ABAP宿主表达式是一种在ABAP7.40及更高版本中引入的特性,‌它允许在SQL表达式的操作数位置或编写SQL语句的工作区中使用任何ABAP表达式。‌ 这种表达式通过在表达式前加上@符号来标识,‌形式为@(abap_expression)。‌宿主表达式的引入,‌使得ABAP开发者能够更灵活地在SQL查询中使用......
  • 正则表达式(分组、零宽断言)
     目录正则表达式分组捕获组编号捕获组(pattern)命名捕获组(?\<name>pattern)非捕获组(?:pattern)零宽断言先行断言零宽正向先行断言(?=pattern1)pettern2零宽负向先行断言(?!pattern1)pettern2后行断言零宽正向后行断言(?<=pattern1)petter......
  • 算术运算符里的特殊运算符
    1.++(自加)给一个数加1自加分为两种,一个是++a,另一个是a++a++:先给数赋值,然后再给a加1++a:先给a加1,然后再给数赋值2.--(自减)给一个数减1......
  • 运算符
    1.算术运算符强转以后:2.算术运算符的一些默认3.逻辑运算符4.取余......
  • 正则表达式
    正则表达式目录正则表达式字符通配符次数通配符字符类定位符分组和量词选择和逻辑运算符边界匹配符转义特殊字符预定义字符类字符通配符.:匹配任意单个字符(除了换行符)。次数通配符*:前一个字符的0次或多次。例如,a*可以匹配"cat"中的"c",也可以匹配"apple"中的"app"......
  • Apple开发_正则表达式相关
    NSString+Regex.h#import<Foundation/Foundation.h>//正则表达式相关@interfaceNSString(Regex)//邮箱验证-(BOOL)is_Email;//手机号码验证-(BOOL)is_Phone_Num;//车牌号验证-(BOOL)is_Car_No;//网址验证-(BOOL)is_Url;//邮政编码-(BOOL)is_......