1013 - 计算表达式的值

题目描述

小明在你的帮助下,破密了Ferrari设的密码门,正要往前走,突然又出现了一个密码门,门上有一个算术表达式,其中只有如下符号:

“(”,“)”,“0~9”,“+”,“-”,“*”,“/”,“^”

其中“^”表示乘方,“/”用整除。

输入的表达式都是合法的,这个表达式的值就是密码。小明数学学得不好,还需你帮他的忙。

输入格式

输入一行字符串,为一个算术表达式。

输出格式

输出一个整数,就是密码。

样例数据 1

输入 

1+(3+2)*(7^2+6*9)/(2)

输出

258

备注

【数据范围】

    100% 的数据满足:整个算式长度<=30,其中所有数据运算结果(包含中间运算结果)都在 231-1 的范围内。

 

分析

我们先来了解一下字符串 string 的使用,以及一些常用函数

substr  取出字符串的一个子串 使用:str2 = str1.substr(5,7)

这个使用的意思就是,取出str1中从第5个位置开始往后数7个位置,这一段字符串,并存在str2中

sscanf 从一个字符串中读入 

其实和scanf是一样的,只是scanf是从屏幕中读,但是sscanf是从你给定的字符串中读取

使用:

if s=" 100 50y "

sscanf(s_c.str(),“%d%d",&a,&b);

这个时候a=100,b=50

sprintf 将一些东西输出到一个字符串里去

其实也和printf差不多,只是printf是输出到屏幕上,sprintf是输出到你给定的字符串中

知道这些常用操作后,做起字符串的题来简直顺溜极了

 

对于这道题而言,由于我们知道计算机比较笨笨的,不会像我们人一样直接判断运算的优先级然后进行计算,它只会按部就班从左往右算。所以我们要体谅它一下,转化一下表达式的样子,然后再交给计算机算

我们维护两个栈,一个是运算符栈,一个是操作数栈

 从左往右扫描字符串,遇到数字就截取这一段数字将其压入操作数栈,遇到运算符就压入运算符栈。在压入运算符的时候,我们需要保证栈顶运算符的优先级低于当前的运算符,然后再压入,如果大于当前的运算符,我们就将其弹出栈,并从操作数栈中取头两个数进行相应运算,再将得到的值压回操作数栈

这样一直进行下去,直到字符串扫描完

为了方便,我们在字符串的一头一尾加上括号

为什么这样搞就是对的呢??

手动模拟一下吧……这很显然

 

代码

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int number[301];   //数字栈
char symbol[301];  //运算符栈
string s,t;        //s为表达式串,t是一个多位数字串
int i,j,p;         //i为s中读数据指针,p为栈指针

int POW(int a,int b)  //求a^b 
{
	int j,t=1;
	for(j=1;j<=b;j++) t*=a;
	return t;
}

void push()        //运算符入栈
{
    p++;
    symbol[p]=s[i];
}

void pop() //运算符栈顶元素出栈,并取出操作数栈栈顶的2个元素完成相应的运算
{
    p--;                 //运算符栈,栈顶运算符出栈
    switch(symbol[p+1])  //数字栈,栈顶2个元素出栈利用刚才出栈的符号运算
    {
         case '+' : number[p]+=number[p+1]; break;
         case '-' : number[p]-=number[p+1]; break;
         case '*' : number[p]*=number[p+1]; break;
         case '/' : number[p]/=number[p+1]; break;  
         case'^'  :number[p]=POW(number[p],number[p+1]);break;		        
    }
}

bool can()         //判断运算符的优先级别,建立是否出栈运算的标志函数
{ 
    if((s[i]=='+' || s[i]=='-') && (symbol[p]!='(' )) return true;  //能出栈运算
    if((s[i]=='*' || s[i]=='/') && (symbol[p]=='^' ||symbol[p]=='*' || symbol[p]=='/')) return true;
    if(s[i]=='^' && symbol[p]=='^') return true;
    return false;   //不能出栈运算
}

int main()
{

    cin>>s;
    s="("+s+")";  //读入表达式并在两端加一对括号
    i=0; p=0;
     
    while(i<s.size())      //扫描字符串
    //一定要注意处理顺序
    {
        while(s[i]=='(' )   //左括号处理
        {
            push();         //左括号入栈 
            i++;
        } 
        
        if(s[i]>='0' && s[i]<='9')
        {
           j=i;
           do             //取连续数字入操作数栈
           {                   
              i++;
           }while(s[i]>='0' && s[i]<='9');
     
           t=s.substr(j,i-j);                   //从s中截取多位串并转成数值型              
           sscanf(t.c_str(),"%d",&number[p]);   //转成整数  
        }                                   

                          //处理数字后面的情况,只能是')'或运算符号两种情况 
      
        if(s[i]==')')    //右括号处理
        {
            while(symbol[p]!='(') pop();  //反复计算括号中的表达式直到左括号为止
            p--;                          //左括号出栈(已经完成运算) 
            number[p]=number[p+1];        //把结果下移到下面一个空格中 
        }
        
        else                      //如果是运算符,根据can值作运算符出栈计算 或 入栈
        {
            while(can()) pop();   //如果新运算符号级别低于栈内符号,则反复出栈运算
            push();               //新符号s[i]入栈
        }
        i++;                      //取下一个字符 
    }
    cout<<number[0]<<endl;        //输出结果 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值