算法比记课后习题 7.1 codeup

版权声明:原创文章,转载请注明出处 https://blog.csdn.net/hza419763578/article/details/88417340

问题 A: 简单计算器

时间限制: 1 Sec  内存限制: 32 MB
提交: 1055  解决: 442
[提交][状态][讨论版][命题人:外部导入]

题目描述

读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。

输入

测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。

输出

对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

样例输入

30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92
0

样例输出

12178.21

人脑熟悉中缀表达式,而计算机熟悉前缀后缀表达式,商业计算机都用后缀表达式,因此先将中缀表达式(输入的字符串)转换为后缀表达式,然后再进行计算

前缀后缀参考

后缀表达式参考2

后缀表达式

简介

后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后

比如:3 4 + 5 × 6 -

后缀表达式计算机求值

与前缀表达式类似,只是顺序是从左至右:

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

例如后缀表达式“3 4 + 5 × 6 -”

  1. 从左至右扫描,将3和4压入堆栈;
  2. 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
  3. 将5入栈;
  4. 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
  5. 将6入栈;
  6. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

将中缀表达式转换为后缀表达式

与转换为前缀表达式相似,步骤如下:

  1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
    1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2. 否则,若优先级比栈顶运算符的高,也将运算符压入s1
    3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;(循环)
  5. 遇到括号时:
    1. 如果是左括号“(”,则直接压入s1;
    2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  6. 重复步骤2至5,直到表达式的最右边;
  7. 将s1中剩余的运算符依次弹出并压入s2;
  8. 依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式(转换为前缀表达式时不用逆序)

例如,将中缀表达式“1+((2+3)×4)-5”转换为后缀表达式的过程如下

扫描到的元素 s2(栈底->栈顶) s1 (栈底->栈顶) 说明
1 1 数字,直接入栈
+ 1 + s1为空,运算符直接入栈
( 1 + ( 左括号,直接入栈
( 1 + ( ( 同上
2 1 2 + ( ( 数字
+ 1 2 + ( ( + s1栈顶为左括号,运算符直接入栈
3 1 2 3 + ( ( + 数字
) 1 2 3 + + ( 右括号,弹出运算符直至遇到左括号
× 1 2 3 + + ( × s1栈顶为左括号,运算符直接入栈
4 1 2 3 + 4 + ( × 数字
) 1 2 3 + 4 × + 右括号,弹出运算符直至遇到左括号
- 1 2 3 + 4 × + - -与+优先级相同,因此弹出+,再压入-
5 1 2 3 + 4 × + 5 - 数字
到达最右端 1 2 3 + 4 × + 5 - s1中剩余的运算符

因此结果为“1 2 3 + 4 × + 5 -”

#include<iostream>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<cctype>//isdigit()
using namespace std;

struct node{
	double num;//当前节点操作数值
	char op;//当前节点操作符
	bool flag;//当前节点到底是操作符还是操作数   true:操作数   false:运算符
};

string str;//记录输入的表达式
stack<node> s;//运算符栈
queue<node> q;//操作数兼后缀表达式中间结果队列(运行完为最后的结果) 
map<char,int> mp;//用map记录运算符优先级别 

//中缀表达式转后缀表达式 
void Change(){
	node temp; //存储当前临时节点 
	for(int i=0;i<str.length();){
		if(isdigit(str[i])){//是操作数
			temp.flag=true;//操作数
			temp.num=str[i++]-'0';
			while(!str.empty()&&isdigit(str[i])){//多位数字      string也有empty
				temp.num=temp.num*10+(str[i]-'0');
				i++;
			}
			q.push(temp);//如操作数队列
		}else{//是运算符
			temp.flag=false;
			temp.op=str[i++];				//注意小于等于不是小于
			while(!s.empty()&&mp[s.top().op]>=mp[temp.op]){//优先级低于运算符栈顶元素 ★★
				q.push(s.top());
				s.pop();
			}
			//然后才能将temp压入运算符栈
			s.push(temp);//压入运算符栈 是s.push不是q.push千万别写错了 ★★
		}
	}

	//★★
	//若最后运算符栈还有运算符,直接全部压入后缀表达式
	while(!s.empty()){
		q.push(s.top());
		s.pop();
	}

	//最终q里的就是最后的后缀表达式
} 

double cal(){
	double x1,x2,ans;
	node temp;
	stack<double> s;//运算数 中间结果栈 最终结果栈
	// while(!s.empty()) s.pop();//初始化清空栈
	while(!q.empty()){
		temp=q.front();
		q.pop();//提前pop()否则忘了陷入死循环
		if(temp.flag){//运算数
			s.push(temp.num);
		}else{//运算符
			x2=s.top();s.pop();
			x1=s.top();s.pop();//注意x2 与 x1的顺序  先出栈的为第二操作数 ★★
			switch(temp.op){
				case '+':
					ans=x1+x2;
					break;
				case '-':
					ans=x1-x2;
					break;
				case '*':
					ans=x1*x2;
					break;
				case '/':
					ans=x1/x2;
					break;
			}
			s.push(ans);//新操作数入栈
		}
	}

	//最终的结果就是答案
	return s.top();
}


int main(){
	mp['+']=mp['-']=0;
	mp['*']=mp['/']=1;
	while(getline(cin,str)&&str!="0"){
		for(string::iterator it=str.begin();it!=str.end();it++){
			if(*it==' ') str.erase(it);
		}
		// cout<<str<<endl;
		Change();
		printf("%.2f\n", cal());
	}
	return 0;
}

问题 B: Problem E

时间限制: 1 Sec  内存限制: 32 MB
提交: 620  解决: 210
[提交][状态][讨论版][命题人:外部导入]

题目描述

请写一个程序,判断给定表达式中的括号是否匹配,表达式中的合法括号为”(“, “)”, “[", "]“, “{“, ”}”,这三个括号可以按照任意的次序嵌套使用。

输入

有多个表达式,输入数据的第一行是表达式的数目,每个表达式占一行。

输出

对每个表达式,若其中的括号是匹配的,则输出”yes”,否则输出”no”。

样例输入

4
[(d+f)*{}]
[(2+3))
()}
[4(6]7)9

样例输出

yes
no
no
no

此题简单,但注意()}}]]]]栈提前空了的清空 不判断的话,s.top()会运行报错

#include<iostream>
#include<stack>
#include<string>
#include<map>
using namespace std;

string str;
map<char,char> mp;

bool isLegal(){
	stack<char> s;
	for(int i=0;i<str.length();i++){
		if(str[i]=='('||str[i]=='['||str[i]=='{'){
			s.push(str[i]);
		}else if(str[i]==')'||str[i]==']'||str[i]=='}'){
			//此时若栈提前空了 也非法 ★★
			if(!s.empty()&&s.top()==mp[str[i]]) s.pop();
			else{
				return false;
			}
		}
	}
	if(!s.empty()) return false;
	else return true;
}

int main(){
	mp[']']='[';
	mp[')']='(';
	mp['}']='{';
	int T;
	while(cin>>T){
		while(T--){
			cin>>str;
			if(isLegal()) cout<<"yes\n";
			else cout<<"no\n";
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hza419763578/article/details/88417340