这题我采用的是基于栈的实现方法。我觉得本题的精髓是定义一个混合栈(既可以存数字又可以存符号,这里参考了别人用结构体数组实现的栈方法,后续还能充当队列使用,相当方便)。
大体上的思路是先定义一个混合栈,然后凡是数字后面有符号的都把它入栈。符号方面因为存在优先级的运算顺序,其处理起来和前一道不带括号的方法一样,即若即将入栈的符号的优先级若大于栈内的就入栈,否则就把栈内的元素出栈加入到混合栈,直到栈顶元素的优先级小于即将入栈的元素。同时因为本题是有括号的,所以最括号也要无条件入栈。
但是出栈的条件要增加一个如果遇到右括号则出栈直到栈顶是左括号,
不过这里要特别注意循环的过程中会出现栈已经空了,但是调用top()的情况,这样会导致RE。(虽然本地上运行没毛病。。。)
最后如果符号栈中还有元素,则要继续出栈加入到混合栈中。(这时的括号直接pop(),因为都是多余的)。
然后运算过程中就混合栈充当队列,超好的。让数组从第一个元素遍历,如果是数字则加入新建的一个数字栈,知道遇到一个符号,就把数字栈的头两个元素pop(),然后根据符号运算,再压入数字栈中。
参考:http://blog.csdn.net/lengxuenong/article/details/50809648
以下为AC代码
#include<cstdio>
#include<stack>
#include<map>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
const int elength=1000;
int ans=0;
stack<int>s1;
stack<char>s2;
stack<int>s3;
char c[elength];
int indx;
struct mixStack{
char opr;
int num;
};
mixStack s5[elength];
void Caculate()
{
for(int j=0;j<indx;j++){
bool vis=false;
//if(!s3.empty())
//cout<<"top:"<<s3.top()<<endl;
if(s5[j].opr==0) {s3.push(s5[j].num);}
else{
int c1,c2;
c1=s3.top();
s3.pop();
if(!s3.empty())
{
c2=s3.top();
s3.pop();
vis=true;
}
switch(s5[j].opr){
case '*':
if(vis)
s3.push(c2*c1);
else
s3.push(c1*0);
break;
case '+':
if(vis)
s3.push(c2+c1);
else
s3.push(c1+0);
break;
case '-':
if(vis)
s3.push(c2-c1);
else
s3.push(0-c1);
break;
case '/':
if(vis)
s3.push(c2/c1);
else
s3.push(0/c1);
break;
case '^':
if(vis)
s3.push(round(pow(c2,c1)));
else
s3.push(round(pow(0,c1)));
break;
default:break;
}
}
}
}
void Poland(){///转换成逆波兰表达式
int i=0;
int cnt=0;
int ii;
bool judge=false;
int temp;
map<char,int> m;
//char c[elength];
//memset(c,0,sizeof(c));
m['+']=1;
m['-']=1;
m['*']=2;
m['/']=2;
m['^']=3;
m['(']=m[')']=0;///定义优先级
while(1)
{
cnt=s1.size()+1;
temp=0;
ii=0;
for(;c[i]-'0'>=0&&c[i]-'0'<=9;i++)
{
s1.push(c[i]-'0');
}
//cnt++;
while(s1.size()>=cnt)//1+1*(3+1
{
//cout<<"top"<<s1.top()<<endl;
judge=true;
temp=temp+s1.top()*pow(10,ii++);
s1.pop();
}///连接数字成一个整数
//cout<<"temp:"<<temp<<endl;
if(judge) {s5[indx++].num=temp;}
judge=false;
if(c[i]=='\0') break;
if(s2.empty()||m[c[i]]>m[s2.top()]||c[i]=='(')
{s2.push(c[i]);}
else if(c[i]==')')
{
while(!s2.empty()&&s2.top()!='('){
s5[indx++].opr=s2.top();
s2.pop();
}
if(!s2.empty()&&s2.top()=='(')
s2.pop();
}
else
{
while(!s2.empty()&&(m[c[i]]<=m[s2.top()]&&s2.top()!='('))
{
//if(s2.empty()) break;
s5[indx++].opr=s2.top();
s2.pop();
}
s2.push(c[i]);
}
i++;
}
while(!s2.empty()){
if(s2.top()=='('||s2.top()==')')
s2.pop();
else{
s5[indx++].opr=s2.top();
s2.pop();
}
}
/*for(int j=0;j<indx;j++){
if(s5[j].opr==0)
cout<<s5[j].num<<endl;
else
cout<<s5[j].opr<<endl;
}*/
}
int main()
{
cin>>c;
Poland();
Caculate();
cout<<s3.top()<<endl;
}
来更新一下二叉树的做法。前面将式子转化成逆波兰式和之前一样。不同的是在转化成逆波兰式后建树处理。如果mixStack出来的是int类型则将节点压入一个inte栈,遇到若mixStack出栈的是符号,则将inte头上的两个元素出栈,与符号节点建立连接。(符号为他们的父节点,数字为叶子节点)。然后后序遍历二叉树,计算。(符号节点的data存储他的子树的值),所以最后输出根节点的值便是答案。以下为AC代码,实际上只需注意build()函数和InOrderTraverse()函数就可以。
#include<cstdio>//test:(3-1)*3+10/2+9
#include<stack>
#include<map>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
const int elength=1000;
int ans=0;
stack<int>s1;
stack<char>s2;
//stack<int>s3;
string c;
int indx;
typedef struct BiTNode{
int data=0;
char op='0';
struct BiTNode *lch,*rch;
}BiTNode,*BiTree;
stack<BiTree> node;
stack<int> inte;
struct mixStack{
char opr;
int num;
};
mixStack s5[elength];
void Build(){
BiTree b,c,a;
for(int j=0;j<indx;j++){
//bool vis=false;
//if(!s3.empty())
//cout<<"top:"<<s3.top()<<endl;
if(s5[j].opr==0){
b=new BiTNode;
b->data=s5[j].num;
b->lch=b->rch=NULL;
node.push(b);
}
else{
b=new BiTNode;
b->op=s5[j].opr;
b->lch=node.top();
node.pop();
if(!node.empty())
{
b->rch=node.top();
node.pop();
}
else
b->rch=NULL;
node.push(b);
}
}
}
int Caculate(int t1,int t2,char opr){
switch(opr){
case '*':
return t1*t2;
case '+':
return t1+t2;
case '-':
return t1-t2;
case '/':
return t1/t2;
case '^':
return round(pow(t1,t2));
default:break;
}
}
/*void InOrderTraverse(BiTree T){
if(T){
InOrderTraverse(T->lch);
InOrderTraverse(T->rch);
if(T->data)
cout<<T->data<<endl;
else
printf("%c\n",T->op);
}
}*/
void InOrderTraverse(BiTree T){
int t1=0,t2=0;
bool vis=false;
if(T){
InOrderTraverse(T->lch);
InOrderTraverse(T->rch);
if(T->data){
inte.push(T->data);
}
else{
if(!inte.empty()){
t1=inte.top();
inte.pop();}
if(!inte.empty()){
t2=inte.top();
inte.pop();
vis=true;}
if(vis==false)
{t2=t1;t1=0;}
vis=false;
T->data=Caculate(t1,t2,T->op);
//cout<<"ans:"<<T->data<<endl;
inte.push(T->data);
}
}
}
void Poland(){///转换成逆波兰表达式
int i=0;
int cnt=0;
int ii;
bool judge=false;
int temp;
map<char,int> m;
//char c[elength];
//memset(c,0,sizeof(c));
m['+']=1;
m['-']=1;
m['*']=2;
m['/']=2;
m['^']=3;
m['(']=m[')']=0;///定义优先级
while(1)
{
cnt=s1.size()+1;
temp=0;
ii=0;
for(;c[i]-'0'>=0&&c[i]-'0'<=9;i++)
{
s1.push(c[i]-'0');
}
//cnt++;
while(s1.size()>=cnt)//1+1*(3+1
{
//cout<<"top"<<s1.top()<<endl;
judge=true;
temp=temp+s1.top()*pow(10,ii++);
s1.pop();
}///连接数字成一个整数
//cout<<"temp:"<<temp<<endl;
if(judge) {s5[indx++].num=temp;}
judge=false;
if(c[i]=='\0') break;
if(s2.empty()||m[c[i]]>m[s2.top()]||c[i]=='(')
{s2.push(c[i]);}
else if(c[i]==')')
{
while(!s2.empty()&&s2.top()!='('){
s5[indx++].opr=s2.top();
s2.pop();
}
if(!s2.empty()&&s2.top()=='(')
s2.pop();
}
else
{
while(!s2.empty()&&(m[c[i]]<=m[s2.top()]&&s2.top()!='('))
{
//if(s2.empty()) break;
s5[indx++].opr=s2.top();
s2.pop();
}
s2.push(c[i]);
}
i++;
}
while(!s2.empty()){
if(s2.top()=='('||s2.top()==')')
s2.pop();
else{
s5[indx++].opr=s2.top();
s2.pop();
}
}
/*for(int j=0;j<indx;j++){
if(s5[j].opr==0)
cout<<"a:"<<s5[j].num<<endl;
else
cout<<"o:"<<s5[j].opr<<endl;
}*/
}
int main()
{
cin>>c;
//c=Except(c);
Poland();
Build();
InOrderTraverse(node.top());
cout<<node.top()->data<<endl;
}