蓝桥杯 公式解析 STL中栈的运用


在某些应用中,为了支持灵活性,往往用到自定义的公式。


比如,有如下的原始公式集合:


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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值