在某些应用中,为了支持灵活性,往往用到自定义的公式。
比如,有如下的原始公式集合:
int add(int x, int y): 返回x与y的和
int add(int x, int y, int z): 返回x,y,z三个数的和
int min(int x, int y): 返回x,y中较小的值
int max(int x, int y): 返回x,y中较大的值
int doubleMe(int x): 返回 x 的2倍
给出一个自定义公式串
add(min(5,3),max(2,8),add(1,doubleMe(1)))
通过手工计算可以得出结果为:14
本题的任务是:编写一个解析程序,能够对由上述原始公式任意组合出来的公式计算其结果。也就是输入一个自定义公式串,输出它的计算结果(可以不考虑输入公式本身有语法错误的情况)。
输入的公式串中可以含有多余的空格,类似:
add( min(5, 3) , max(2 , 8) ) 也是合法的公式。
程序输入:公式串
程序输出:该公式的计算值
这种公式在计算的时候都是从内层开始,但遍历的时候是从外层开始的,为了计算,很自然就会想到栈这种先进后出的数据结构,当然可以自己写一个栈,但STL中实际上提供了栈<stack>,下面再分析一些如何运用栈来解公式的值:
首先,为了方便起见,将公式中的所有空格有去掉,这样在之后就不用考虑空格这种情况了。
我们需要3个栈:1.method 用来保存函数名,2.num 用来保存函数的参数,3.count 用来保存每个函数中参数的个数(其实主要是用来区分两个不同的add()的)
然后,我们从第一个字符开始遍历,当遇到add时,就把add压入栈,遇到min就把min压入栈,每次压入栈之后,还要将数字0压入count栈,从而给每个函数配置一个参数计数器。
需要注意的是,当遇到数字的时候,因为字符串中的数字是字符,而且数字的位数也是不确定的,我们需要先将数字这个字符串提取出来,然后通过处理成为一个真正的数字,每次提取出一个数字,都要将count栈顶的数值加1,表示增加一个参数。
最后,通过观察不难发现,每次遇到“)”时,都意味着一个函数的结束,需要处理这个函数,并且这个函数肯定是最内层的函数,所以我们就把“)”作为一个触发标志,每次遇到之后,首先从method栈中弹出一个操作符op,从count栈中弹出一个参数个数c,然后根据c的大小从num栈中取数,根据操作符调用相关的函数,将参数代入,从而获得一个新计算出的数值,将这个数值作为一个新的参数打入nun栈中,同时将count栈顶的数值加1,标志参数的个数增加1,但是当到最外层的函数运算式,比如add(a,b,c),得到的数值打入num栈中之后,没有必要再把count栈顶的元素数值加1,因为运算已经结束了。
当运算停止的时候,只要输出num栈的栈顶元素,那个就是我们要求得数值。
#include<iostream>
#include<stack>
#include<string>
#include<queue>
#include<cstring>
#include<memory.h>
#include<cmath>
using namespace std;
struct Pos
{
int s;
int e;
};
int add(int x,int y)
{
return x+y;
}
int add(int x,int y,int z)
{
return x+y+z;
}
int min(int x,int y)
{
return x<y?x:y;
}
int max(int x,int y)
{
return x>y?x:y;
}
int doubleMe(int x)
{
return 2*x;
}
int main()
{
stack<string> method;
stack<int> num;
stack<int> count;
char exp[1000],exp_t[1000];
int len,i,j,p;
int n[20];
gets(exp_t);
len=strlen(exp_t);
p=0;
memset(exp,'\0',sizeof(exp));
for(i=0;i<len;i++)
{
if(exp_t[i]!=' ')
exp[p++]=exp_t[i];
}
len=p;
for(i=0;i<len;i++)
{
if(exp[i]=='a'&&exp[i+1]=='d')
{
method.push("add");
count.push(0);
}
else if(exp[i]=='m')
{
if(exp[i+1]=='i')
method.push("min");
else
method.push("max");
count.push(0);
}
else if(exp[i]=='d'&&exp[i+1]=='o')
{
method.push("doubleMe");
count.push(0);
}
else if(exp[i]>='0'&&exp[i]<='9')
{
p=0;
for(;exp[i]!=','&&exp[i]!=')';i++)
{
n[p++]=(int)(exp[i]-'0');
}
int temp=0;
for(j=0;j<p;j++)
{
temp+=n[p-j-1]*pow(10,j);
}
num.push(temp);
temp=count.top()+1;
count.pop();
count.push(temp);
}
if(exp[i]==')')
{
string op=method.top();
method.pop();
int c=count.top();
count.pop();
for(j=0;j<c;j++)
{
n[j]=num.top();
num.pop();
}
if(op=="add")
{
if(c==3)
{
num.push(add(n[0],n[1],n[2]));
}
else if(c==2)
{
num.push(add(n[0],n[1]));
}
}
else if(op=="min")
{
num.push(min(n[0],n[1]));
}
else if(op=="max")
{
num.push(max(n[0],n[1]));
}
else if(op=="doubleMe")
{
num.push(doubleMe(n[0]));
}
if(count.size())
{
c=count.top()+1;
count.pop();
count.push(c);
}
}
}
cout<<num.top()<<' ';
return 0;
}