简单计算器——两种方法

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

输入:
1 + 2
4 + 2 * 5 - 7 / 11
0
输出:
3.00
13.36

这种类型题写了很多,但每次变化一点点就会卡很久,而且中缀转后缀也一直不熟练。。今天再用两种方法总结一次

方法一:后缀式法

相比于之前写的中缀式转后缀式,遇到的问题有:

  1. 常量不再用a,b,c表示,而是具体的常数,这就导致不再能用一个字符栈来存储后缀表达式,必须将操作数从字符串中提取并组合起来,再用操作数栈和运算符栈分开存放。
  2. 总是思维惯性的想着求出后缀式之后,再用一个栈对后缀式求值,然而在不能用一个字符栈存后缀式的情况下,这是很复杂的。其实可以在每次向后缀式添加运算符时直接求值啊!
  3. 56和61两行写错了,在vs下才找出问题
#include<bits/stdc++.h>
using namespace std;

map<char,int> isp;
map<char,int> icp;
stack<double> num;    //操作数栈 
stack<char> s;	   //运算符栈 
string str;		   //键盘输入的中缀式 
string post;	//后缀式  但在本题中,每次向后缀式添加运算符时 改为直接计算即可,故无需用到后缀式 

int getNum(int i)
{
	double numb = 0;
	while(str[i] >= '0' && str[i] <= '9') {
		numb = numb * 10 + str[i++] - '0'; 
	}
	num.push(numb);
	return i;
}

void cal(char op)
{
	double s2 = num.top();
	num.pop();
	double s1 = num.top();
	num.pop();
//	cout << s1 << op << s2 << endl;
	switch(op){
		case '+':
			num.push(s1+s2);	break;
		case '-':
			num.push(s1-s2);	break;
		case '*':
			num.push(s1*s2);	break;
		case '/':
			num.push(s1/s2);	break;
	}
}

int main()
{
	isp['*'] = 5;isp['/'] = 5;isp['+'] = 3;isp['-'] = 3;
	icp['*'] = 4;icp['/'] = 4;icp['+'] = 2;icp['-'] = 2;
	while(getline(cin,str)){
		//num.clear(); s.clear(); 栈好像没有clear()方法,不过不清空也问题不大 
		for(int i=0;i<str.length();i++){
			if(str[i] == ' ')
				continue;
			else if(str[i] >= '0' && str[i] <= '9')
				i = getNum(i);  //返回的i指向操作数后的空格 ,操作数存在操作数栈中 
			
			else{ //运算符 
				if(s.empty() || icp[str[i]] > isp[s.top()])
					s.push(str[i]);
				else{
					while(!s.empty() && icp[str[i]] < isp[s.top()]){ //!s.empty()必须写在前面(思考原因)
	//					post += s.top();//要求输出后缀式时的写法 
						cal(s.top());	//直接计算的写法 
						s.pop();
					}
					s.push(str[i]); //差点忘记 
				} 
			} 
		}
		while(!s.empty()){
			cal(s.top());
	//		post += s.top();//
			s.pop();
		}
		printf("%.2f\n",num.top());  //栈顶元素即为最终答案 
	}
}

方法二:直接扫描

这种方法很贴近正常思维,先对*/运算,再对+ -运算,最后统一运算。
但问题是如果题目中还要求考虑括号对优先级的影响,怕是就无能为力了,但不失为一个好方法。

#include<iostream>
using namespace std;
int main()
{
    int d = 0, pos = -1; char op = {0};
    double nums[201] = { 0 };
    while (cin>>d)  //取第一个操作数
    {
        if (-1 == pos && 0 == d && '\n' == getchar()) break;
        nums[++pos] = d;
        while (cin>>op>>d)  //后面每次连运算符带操作数一起取
        {
            switch (op)
            {
                case '+': nums[++pos] = d; break;	//加减,在下一个位置储存
                case '-': nums[++pos] = -d; break;
                case '*': nums[pos] *= d; break;    //乘除,就在原地处理
                case '/': nums[pos] /= d; break;
            }
        }
        double sum = 0; 
        while (pos >= 0) 
        	sum += nums[pos--];  //最后统一进行加运算
        printf("%.2f\n", sum); getchar();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值