表达式求值(2) | c++ | 栈

一、题目描述

问题描述

  带有变量的中缀表达式是常见的数学表达式。如果规定变量由长度不超过 8 个小写字母组成;end为保留字,表示程序段结束;用?表示输出指定变量的值,则可以设计出比较复杂的表达式(即一个可顺序执行语句序列)。例如,如果有如下语句段:

abc=10
def=8
c=abc+def
abc=abc+5-c*2
? c
? abc
end

则输出为:

c=18
abc=-21

注意:为了简化编程实现,运算符只有+,-,*,/ ,%和^(指数运算),可以处理圆括号(),并假定输入的算术表达式正确。

要求:使用栈结构实现。

输入:表达式序列

输出:全部指定变量的值

表达式中的全部计算结果均为整数。如果在计算过程中出现除数为0的情况,则输出:Divide 0.

特殊情况说明:
在表达式中,如果操作数出现负数(例如-8),则要特别注意。例如:
10加-8表示为:10+-8。
10减-8表示为:10--8。

测试输入 期待的输出 时间限制 内存限制 额外进程
测试用例 1 以文本方式显示
  1. abc=10↵
  2. def=8↵
  3. c=abc+def↵
  4. abc=abc+5-c*2↵
  5. ? c↵
  6. ? abc↵
  7. end↵
以文本方式显示
  1. c=18↵
  2. abc=-21↵
1秒 64M 0
测试用例 2 以文本方式显示
  1. a=12↵
  2. b=5↵
  3. c=a/b↵
  4. d=(a+1)%(b+1)↵
  5. e=a^2↵
  6. f=-12+a↵
  7. g=(a+5)*d-c↵
  8. ? c↵
  9. ? d↵
  10. ? e↵
  11. ? f↵
  12. ? g↵
  13. a=a+10↵
  14. ? a↵
  15. end↵
以文本方式显示
  1. c=2↵
  2. d=1↵
  3. e=144↵
  4. f=0↵
  5. g=15↵
  6. a=22↵
1秒 64M 0
测试用例 3 以文本方式显示
  1. abc=3↵
  2. ab=2^(abc-1)^(5-abc)↵
  3. ? ab↵
  4. end↵
以文本方式显示
  1. ab=16↵
1秒 64M 0
测试用例 4 以文本方式显示
  1. a=2↵
  2. b=a^(a+1)^(10-8)↵
  3. ? b↵
  4. end↵
以文本方式显示
  1. b=512↵
1秒 64M 0
测试用例 5 以文本方式显示
  1. a=10↵
  2. ? a↵
  3. b=-10+10↵
  4. ? b↵
  5. a=-10-10↵
  6. ? a↵
  7. c=a+-10+-10↵
  8. ? c↵
  9. d=-20+-8-8↵
  10. ? d↵
  11. e=a-12*-2↵
  12. ? e↵
  13. f=80--10+2↵
  14. ? f↵
  15. g=-10--10↵
  16. ? g↵
  17. h=-10+-10↵
  18. ? h↵
  19. i=(90)↵
  20. ? i↵
  21. k=(-100)↵
  22. ? k↵
  23. end↵
以文本方式显示
  1. a=10↵
  2. b=0↵
  3. a=-20↵
  4. c=-40↵
  5. d=-36↵
  6. e=4↵
  7. f=92↵
  8. g=0↵
  9. h=-20↵
  10. i=90↵
  11. k=-100↵
1秒 64M 0
测试用例 6 以文本方式显示
  1. abcdefgh=4↵
  2. ten=10↵
  3. a=18-32↵
  4. ? a↵
  5. b=18/abcdefgh↵
  6. ? b↵
  7. c=18%(b-1)↵
  8. ? c↵
  9. d=ten+(ten+ten)*abcdefgh↵
  10. ? d↵
  11. e=ten-2*ten/abcdefgh↵
  12. ? e↵
  13. f=(18-3)*3↵
  14. ? f↵
  15. ten=ten*(ten)↵
  16. ? ten↵
  17. ten=ten/10↵
  18. ten=(ten+2)/(8-ten)↵
  19. ? ten↵
  20. h=(2*3)/(5*2)↵
  21. ? h↵
  22. ten=10↵
  23. x=ten-(80-30)/3*3+abcdefgh↵
  24. y=(((2+8)*2-(2+abcdefgh)/2)*2-8)*2↵
  25. z=(((8+2)*(abcdefgh/2)))↵
  26. ? x↵
  27. ? y↵
  28. ? z↵
  29. end↵
以文本方式显示
  1. a=-14↵
  2. b=4↵
  3. c=0↵
  4. d=90↵
  5. e=5↵
  6. f=45↵
  7. ten=100↵
  8. ten=-6↵
  9. h=0↵
  10. x=-34↵
  11. y=52↵
  12. z=20↵
1秒 64M 0

二、思路提示

1、从输入入手

输入为若干行,可以分为以下三种:

①带等号的常规赋值式或四则运算

②以问号开头代表需要输出变量的值

③end

2、关于变量

考虑使用结构体来存储。

#define N 110
typedef struct {
	string name;
	int value;
} VRBL;
VRBL v[N];

        声明VRBL是一个结构体。每个v表示一个变量,v.name是这个变量的名称,v.value是这个变量当前的值。

还是使用string,非常的方便,真的是干净又卫生啊。

3、关于四则运算

还是栈,做过很多题目了,此处不再赘述。

三、完整代码

这道题目虽然是选做,不过论难度那还真是不难。

#include<bits/stdc++.h> 
using namespace std;
#define N 110
typedef struct {
	string name;    //name是变量的名字,例如abc,e等。
	int value;      //value是变量的值。
} VRBL;
VRBL v[N];

//若返回值大于1,表示运算符;若返回1,表示是数字;若返回0,表示既不是运算符也不是数字,也就是字母。注意,这里面是不考虑等于号的。
int valu(char c) {
	if ( c==')' )					  return 6;
	if ( c=='^' ) 					  return 5;
	if ( c=='*' || c=='/' || c=='%' ) return 4; 
	if ( c=='+' || c=='-' ) 		  return 3;
	if ( c=='(' ) 					  return 2;
	if ( c>='0' && c<='9' )			  return 1;
									  return 0; 
}

//两个数之间的计算
void cal(int *a1, int a2, char op) {
	switch (op){
		case '+': (*a1) = (*a1) + a2; break;
		case '-': (*a1) = (*a1) - a2; break;
		case '*': (*a1) = (*a1) * a2; break;
		case '/': (*a1) = (*a1) / a2; break;
		case '%': (*a1) = (*a1) % a2; break;
		case '^': (*a1) = pow((*a1),a2); break;
	}
}

int main(){
	
	int valu(char);
	void cal(int*, int ,char);
	
	string Formula;
	int n=0;	//n用来统计变量的个数 
	while (cin>>Formula,Formula!="end") {
		
        //如果是问号
		if (Formula.find('?')!=-1) {
			
			cin >> Formula;
			//遍历一次v,找到相应的变量
			int i;
			for (i=0;i<=n;i++) {
				if (Formula==v[i].name) {
					break;
				}
			}
			cout << v[i].name << '=' << v[i].value << endl;
		}
		
		else {
			//执行通常的赋值或计算
			int target, digit=0; //digit用来遍历Formula,target是待赋值的变量 
			string tpry;         //tpry用来暂时存放读入的字符串内容 
			
			//找到待赋值的变量 
			while (Formula[digit]!='=') {
				tpry+=Formula[digit];
				digit++;
			} digit++;
			
			//将待赋值的变量在v中进行匹配,如果已经有了就直接套用,否则就加入新的 
			if (n==0) {
				target = 0;
				v[0].name = tpry;
				n++;
			}
			else {
				int flag=0;
				for (int i=0;i<n;i++) {
					if (tpry==v[i].name) {
						flag=1;
						target = i;
						break;
					}
				} 
				if (flag==0) {
					target = n;
					v[n].name = tpry;
					n++;
				}
			}
			
			//计算等号后面的内容
			stack<int> Svalue;	//Svalue用来存储值 
			stack<char> Sop;	//Sop用来存储运算符 
			
			int len = Formula.length(), start=digit, flag=1; //flag用来标记正负数
			while ( digit<len ) {
				
				if ( valu( Formula[digit] )==1 )
				//数字 
				{ 
					int cnt=0;
					while ( digit<len && valu(Formula[digit])==1 ) {
						cnt = cnt * 10 + Formula[digit] - '0';
						digit++;
					}
					Svalue.push(cnt*flag);
					flag=1;
				}
				
				else if ( valu( Formula[digit] )>1 )
				//运算符
				{
					if ( Sop.size()==0 ) {
						if (digit==start && Formula[digit]=='-') flag = -1;
						else Sop.push( Formula[digit] );	
					}
					else {
						//Sop不为空
						//负数 
						if ( digit>start && Formula[digit]=='-' && valu(Formula[digit-1])>1 ) {
							flag=-1;
						}
						
						//左括号 
						else if (Formula[digit]=='(' ) {
							Sop.push( Formula[digit] ); 
						}
						
						//右括号
						else if (Formula[digit]==')' ) {
							while ( Sop.size() && Sop.top()!='(' ) {								
								char c = Sop.top();	Sop.pop();
								int a = Svalue.top(); Svalue.pop();
								cal(&Svalue.top(), a, c);
							} 
							Sop.pop();
						}
						
						else {
                            //连续乘方
							if ( Sop.size() && Formula[digit]=='^' && Sop.top()=='^' ) {
								Sop.push('^');
							}
							else {
								if ( Sop.size() && valu(Formula[digit])<=valu(Sop.top()) ) {
									while ( Sop.size() && valu(Formula[digit])<=valu(Sop.top()) ) {
										char c = Sop.top();	Sop.pop();
										int a = Svalue.top(); Svalue.pop();
										cal(&Svalue.top(), a, c);
									}
									Sop.push(Formula[digit]);
								}
								else {
									Sop.push(Formula[digit]);
								}
								
							}
						}	
										 
					}
					digit++;
				}
				
				else if ( valu( Formula[digit] )==0 )
				//字母 
				{
					//找到完整的变量名称
					string word;
					while ( digit<len && valu(Formula[digit])==0 ) {
						word += Formula[digit];
						digit++;
					}
					//匹配并且取值,将其值存入栈
					for (int i=0;i<n;i++) {
						if (v[i].name==word) {
							Svalue.push(v[i].value*flag);
							flag=1;
							break;
						}
					}
				}	
			}

			//补刀
			while ( Sop.size() ) {
				int a = Svalue.top(); Svalue.pop();
				cal(&Svalue.top(), a, Sop.top());
				Sop.pop();
			}
			
			//为目标变量赋新值
			v[target].value = Svalue.top(); 
			
		}
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_70241024/article/details/127093358