計算表示式的值
題目描述
小明在你的幫助下,破密了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;
}