我寫了以下代碼:
//1356:計算(calc)
/*基本思路:后面優先級高,前面內容入棧,否則先算前面內容*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const N=2e6+2;
int stack1[N*2],cnt,x,y,x0,tp1,tp2;
char stack2[N],ch,ch0;
string s;
//計算運算優先組,后面優先級高就前面內容入棧,后面優先級小於等於前面優先組就先算棧內內容
int level(char p)
{
if(p=='+'||p=='-')return 1;
if(p=='*'||p=='/')return 2;
if(p=='^')return 3;
return 0;
}
int cf(int x,int y)//一個簡單快速冪求x^y
{
if(y==0)return 1;
if(y==1)return x;
int t=cf(x,y/2);
t*=t;
if(y%2)t*=x;
return t;
}
//完成一次基本計算
void calc()
{
int x,y;//定義兩個操作數
char ys;//定義一個運算符
ys=stack2[tp2--];
y=stack1[tp1--];
x=stack1[tp1];//運算一次取出兩個數,並把計算結果存回,故此處沒減棧頂指針
switch(ys)
{
case '+':stack1[tp1]=x+y;break;
case '-':stack1[tp1]=x-y;break;
case '*':stack1[tp1]=x*y;break;
case '/':stack1[tp1]=x/y;break;
default:stack1[tp1]=cf(x,y);//也可以直接用庫函數pow(x,y)
}
}
int main(){
s[++cnt]='(';
while((ch=getchar())&&ch!=13&&ch!=10)s[++cnt]=ch;
s[++cnt]=')';
for(int i=1;i<=cnt;i++)
{
ch=s[i];//ch可能為(、)、數字(包括負號)、和運算符
if(ch=='(')stack2[++tp2]='(';
//遇到)就計算到(為止。遇到(之前,棧內所存運算符應該逐級上升,故需反向運算
//如1+2*3^4
else if(ch==')')
{
while(stack2[tp2]!='(')calc();
tp2--;//讓(出棧
}
else if(ch>='0'&&ch<='9'||ch=='-'&&s[i-1]=='(')
//讀到的是數字,把連續的數字變成數值 ,如果是'-'先判斷前面是不是(,是則說明是負號不是減號
{
if(ch=='-')x0=0,y=-1;//y代表數值的符號
else x0=ch-'0',y=1;
ch0=s[++i];
while(ch0>='0'&&ch0<='9')x0=x0*10+ch0-'0',ch0=s[++i];
i--;
x0*=y;
stack1[++tp1]=x0;
}
else //ch為運算符
{
while(level(ch)<=level(stack2[tp2]))calc();
//當前運算符不超過棧頂運算,先算棧頂運算
//此處未判斷運算符棧是否為空是因為棧底是一個(,運算級最低,不可能超過當前運算等級
stack2[++tp2]=ch;//直到當前運算符高於棧頂運算符再把運算符存棧
}
}
cout<<stack1[tp1]<<endl;
return 0;
}
有兩個問題:1、在windows版DEV下運行結果如下
而且,在出現答案258后至少會等待3秒以上程序才會結束。(多次測試都是)
2、提交到網站后答案錯誤4個,運行錯誤一個。
然而,就這同一個思路改成直接用stl中的stack,得到如下代碼:
//1356:計算(calc)
/*基本思路:后面優先級高,前面內容入棧,否則先算前面內容*/
#include<iostream>
#include<stack>
#include<cmath>
#include<cstring>
using namespace std;
int const N=1e5+1;
int x,y;
char ch,ch0;
string s;
stack<int>s1;
stack<char>s2;
//計算運算優先組,后面優先級高就前面內容入棧,后面優先級小於等於前面優先組就先算棧內內容
int level(char p)
{
if(p=='+'||p=='-')return 1;
if(p=='*'||p=='/')return 2;
if(p=='^')return 3;
return 0;
}
//完成一次基本計算
void calc()
{
int m,n;
char z;
n=s1.top();
s1.pop();
m=s1.top();
s1.pop();
z=s2.top();
s2.pop();
switch(z)
{
case '+':s1.push(m+n);break;
case '-':s1.push(m-n);break;
case '*':s1.push(m*n);break;
case '/':s1.push(m/n);break;
default:s1.push(pow(m,n));
}
return;
}
int main(){
cin>>s;
s='('+s+')';
int i=0;
ch='(';
do
{
if(ch=='(')
{
s2.push('(');
}
//遇到)就計算到(為止。遇到(之前,棧內所存運算符應該逐級上升,故需反向運算
//如1+2*3^4
else if(ch==')')
{
while(s2.top()!='(')calc();
s2.pop();//彈出(
}
else if(ch>='0'&&ch<='9'||ch=='-'&&s[i-1]=='(')
//讀到的是數字,把連續的數字變成數值 ,如果是'-'先判斷前面是不是(,是則說明是負號不是減號
{
if(ch=='-')x=0,y=-1;//是負號則符號設為-1,初始值為0
else x=ch-'0',y=1;//默認符號為正
ch0=s[++i];
while(ch0>='0'&&ch0<='9')x=x*10+ch0-'0',ch0=s[++i];
i--;
x*=y;
s1.push(x);
}
else //ch為運算符
{
while(level(ch)<=level(s2.top()))//當前運算符不超過棧頂運算,先算棧頂運算
{
calc();
}
s2.push(ch);//直到當前運算符高於棧頂運算符再把運算符存棧
}
}while(ch=s[++i]);
cout<<s1.top()<<endl;
return 0;
}
便沒有任何問題,提交后也全正確,萬能的網絡朋友們,請幫我看看第一個代碼錯在哪了?
錯因分析:對於一個string,雖然它跟char[]類似,但也不完全相同。它有固定結尾('\0'),是一個字符串結束的標記。雖然我們能像char[]一樣一個一個地改變每一個字符的值,但,修改后的字符串並沒有被系統認可。比如string s="a",這個字符串只有一個字符,存儲在內存中其實是兩個位置:s[0]='a',s[1]='\0'。字符串長度可用s.size()獲得,當然這個值是1(‘\0'結束標記不納入計數之列),如果我們人為修改s[1]='b',盡管你可以再加上一句:s[2]='\0',(感覺像是做錯后的掩飾),但此時測試s.size()=1,這就說明我們修改字符方式加入的'b'並沒有被字符串接受。此時如果想輸出字符串,比如:cout<<s;結果也是a,沒有b。再做一個測試:string s="a"; s[1]='b'; s[2]='c'; s[3]='d';此時,若cout<<s;可得到a。如果輸出s[1]、s[2]、s[3]都可以得到相應的字符。若再加上一句: s+='e';然后cout<<s;顯示結果會是如何?答案是ae。如果你繼續顯示s[1]、s[2]、s[3],那會是'\0'。
或許可以換個角度理解:string s;定義了,再賦值,或定義時就賦值,一旦賦值完成,那么與s等效的字符數組就確定了,數組的最大下標也就確定了(s.size()就代表字符串的長度,也可以說是字符數組不越界能訪問的最大下標),如前文所說s="a",那s[2]實質上已經發生下標越界了,內存數據將會混亂,在本機還能運行,可能由於開發系統的保護抑或這個混亂尚未造成可見的錯誤,但在真實測試數據(數據量遠比樣例大得多)到來,又離開了IDE的保護,錯誤就顯現出來了。這或許可以這么說:你的錯誤操作未必會得出錯誤結果。
如果想增加一個字符'b’並被系統認同,當然也很簡單:s+='b';,這一個操作的背后,除了在后面加了一個字符外,還實時地修改了s.size(),這個操作是配套的,也就是說同步修改了數組的邊界,那就不會發生下標越界問題了。還有一事大家需要明白:s.size()是不可人為手動修改的。比如s.size()=3;這是錯誤的。顯然嘛,你看size后面有一個括號,說明它是一個函數返回值,沒有輸入功能啊。所以,手動修改s[3]='b'這樣的操作沒辦法同步邊界,越界和錯誤是必須的。
要想糾正這個錯誤那就簡單了,方法也很多,本文就不討論了。(參看第二版本)(寫第一版本輸入本想試下不同的輸入方法的,沒想搞出這么大一烏龍,收不到場了。)
謝謝之江學院石老師的不斷指點!!!