1. 程式人生 > >計算表示式的值

計算表示式的值

題目描述

小明在你的幫助下,破密了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;
}