stack的应用-《算法笔记》第7章 简单计算机(含+-*/,codeup1918 )

最近准备企业实习和夏令营/预推免,计划从现在开始到四月底,把数据结构和算法全部复习一遍,主要是参考了《算法笔记》(胡凡、曾磊等著)这本书,从第七章提高篇开始,大约一周推进一章。

由于不是初学者了,在编程过程中会经常使用stack、queue等接口,以及vector、set、map等容器,从而更加方便快捷地实现。

在复习的过程中,我会从CSP认证考试,本书(很多例题来自于浙大PAT以及codeup),LeetCode(力扣),以及蓝桥杯等平台中选取一些典型的题目,作为训练,并且加以总结和整理。

《算法笔记》第7章 提高篇(1)——数据结构专题(1)

7.1 的应用

例题【codeup 1918】

题目描述:读入一个只包含+,-,*,/的非负整数计算表达式,计算表达式的值

输入格式:5 + 2 * 3 / 49 - 4 / 13

输出:4.81

解决思路

第一步 中缀转后缀(对应Change()函数)

1)创建一个操作符栈(stack<node>s),临时存放操作符;

      创建一个队列(或数组)(queue<node>q),存放后缀表达式

2)从左向右扫描中缀表达式

        若读到操作数(注意这边因为每次只读一个字符,所需当连续读到多个数字字符时要做一个转换,比如'2''2''3'转化为223,用一个while{ }循环即可);

        若读到操作符,需要比较优先级

  • 当读到的操作符的优先级高于栈顶操作符优先级,压入栈顶
  • 当读到的操作符的优先级低于或等于栈顶操作符优先级,则将栈中操作符不断弹出,到后缀表达式,直至读到的操作符的优先级高于栈顶操作符优先级,再压入栈顶

3)扫描完成后,将栈中剩余元素依次弹至后缀表达式队列(或数组)中

第二步 计算后缀表达式(对应Cal()函数)

从左到右扫描后缀表达式

若为操作数,压入栈

若为操作符,从栈中连续弹出两个操作数,先弹出的是第二个操作数(如除法中的被除数),后弹出的是第一个操作数(如除非中的除数),计算以后将生成的结果压入栈

如此反复,直至后缀表达式扫描完毕,这时候栈中只有一个数,也即是最终运算结果。

代码及注释如下

#include<iostream>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<map>
using namespace std;
struct node{
	double num;//操作数
	char op;//操作符
	bool flag;//true表示操作数 false表示操作符
};

string str;

stack<node>s;//操作符栈
queue<node>q;//后缀表达式序列(也可以用数组 这里为了练习队列使用queue)
map<char,int>op;//用map建立操作符和优先级映射(不用map直接if判断也行 这里为了练习map)

void Change(){//函数Change()将中缀表达式转化为后缀表达式
	double num;
	node temp;
	for(int i=0;i<str.length();){
		if(str[i]>='0'&&str[i]<='9'){//若为操作数
			temp.flag=true;
			temp.num=str[i++]-'0';
			while(i<str.length()&&str[i]>='0'&&str[i]<='9'){
				temp.num *= 10;
				temp.num += (str[i]-'0');
				i++;
			}//因为是字符串形式,且每次只读一个字符,因此连续读入多个数字字符时需要转化为数字
			q.push(temp);
		}else{//若为操作符
			temp.flag=false;
			while(!s.empty()&&op[str[i]]<=op[s.top().op]){
			//若op的优先级低于或等于栈顶操作符的优先级,则将操作符栈的操作符不断弹出到后缀表达式中 e.g. 3+2*5 该表达式中2*5需要先计算,因此/*/先入队列(位置越前越先计算);	
			//注意:是低于或等于,e.g. 2/3*4 中2/3要先计算 所以'/'需要先进后缀表达式队列
				q.push(s.top());
				s.pop();
			}
			temp.op = str[i];//	若op的优先级高于栈顶操作符的优先级,则压入操作符栈 e.g. 
			s.push(temp);
			i++;
		}
	}
	while(!s.empty()){//上述操作结束后,若操作栈中还有元素,则依次弹出至后缀表达式中
		q.push(s.top());
		s.pop();
	}
}

double Cal(){//计算后缀表达式
	double temp1,temp2;//操作数1 操作数2
	node cur,temp;
	while(!q.empty()){
		cur=q.front();//
		q.pop();
		if(cur.flag==true) s.push(cur);//如果是操作数,则压入栈
		else{
			temp2 = s.top().num;//这里要注意先pop的是运算时的第二个操作数(如除非中的除数)
			s.pop();
			temp1 = s.top().num;//后pop的是第一个操作数(如除非中的被除数)
			s.pop();
			temp.flag = true;
			if(cur.op=='+')temp.num = temp1+temp2;
			else if(cur.op=='-')temp.num=temp1-temp2;
			else if(cur.op=='*')temp.num=temp1*temp2;
			else if(cur.op=='/')temp.num=temp1/temp2;
			s.push(temp);
		}
	}
	return s.top().num;
}
int main(){
	op['+']=op['-']=1;//利用map设定操作符优先级
	op['*']=op['/']=2;
	while(getline(cin,str),str!="0"){
		for(string::iterator it=str.end();it !=str.begin();it--){
			if(*it==' ')str.erase(it);//string的erase()可以消除空格
		}
		while(!s.empty())s.pop();//初始化栈
		Change();
		printf("%.2f\n",Cal());
	}
}

示例及运行结果

 扩展

若表达式中出现( ),处理也很简单,只需要在中缀转后缀时加一个判断,即读到')'则压入栈,读到')'则将栈中元素不断弹出直至遇到'(',因为括号决定了部分表达式的优先级,括号里的要优先计算,所以遇到')'就弹出括号内的内容到后缀表达式中即可。

相关题目

CSP 201903-2 二十四点

括号匹配()【】{}  今天下午微软面试的也问到了

Codeup Contest ID:100000605 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值