基于逆波兰表达式的公式解析器-算法和思路(二)

37 篇文章 0 订阅
11 篇文章 0 订阅

续:

       接着说基于逆波兰表达式的公式解析器的实现思路。下面是加入函数、符号重载后的算法描述,其实也没多大变化,只是算法在处理上更细化,更详细,更接近实际环境。

改进的算法描述:

       1.构建两个栈Operand(操作数栈)和Operator(操作符栈)和一个LAST_TOKEN标记字段。

       2.扫描给定的字符串,扫描时注意跳过空格,提取完整的操作数、操作符和函数。

       3.如果获得一个运算符(用B代替)首先构造响应的运算符,构造时需要比较LAST_TOKEN记录字段,来判断重载的操作符的含义,比如如果LAST_TOKEN是数字,那么“-”就是一个数学运算符,如果LAST_TOKEN是运算符,那么要看“-”后面是不是数字,如果是数字,则认为“-”是“负号”。构造好Operator后和Operator栈栈顶元素(用A替代)比较:

              1)如果A不存在,则把B压入Operator栈中;

              2)如果B是一个左括号,则忽略A和B的优先级比较,把B压入Operator栈。

              3)如果B是逗号,同样忽略A和B的比较,把B压入Operator栈。

              4)如果B是一个右括号,则把Operator栈顺序出栈,然后把弹出的元素顺序压入Operand栈中,出栈是需要判断逗号情况,如果是逗号,则不入栈,记录逗号个数,直到栈顶弹出的是左括号,括号不入Operand栈中。之后看Operator栈顶元素,如果栈顶元素是函数类型,则把函数Operator出栈然后将逗号个数+1构造数字操作数压入Operand栈中,然后把函数Operator也压入Operand栈中。

              5)如果A是左括号,则把B直接压入Operator栈。

              6)如果B优先级比A高,则把B直接压入Operator栈。

              7)如果B优先级低于或等于A的优先级,则把A出栈然后压入Operand栈,反复进行此步骤直到栈顶优先级高于B的优先级或者栈顶是一个括号。

       4.扫描完毕后,把Operator栈的元素依次出栈,然后依次压入Operand栈中。


算法特点:

       (1)和原来的逆波兰表达式处理上没什么不同,但是改进的算法中,描述清了更多的计算符号。

       (2)整个处理过程中,使用一个Flag来记录最近一次的符号类型,这个Flag将帮助我们判断重载的符号的符号意义,比如最近一次的符号是一个Operand那么“-”可以判断代表的是减法操作符,但是如果Flag是Operator那么“-”应该代表的是负号。

       (3)处理函数时,先统一处理为UnknownFun,等函数执行的时候,我们向函数管理器请求实际执行对象,这样在解析的时候可以不用同时判断函数是否受支持,方便我们的程序扩展。

公式求值:

逆波兰表达式的公式求值就是一个简单的弹Stack操作,实现起来更简单。我们只需要注意的是,我们的运算规则因为不仅仅是算术运算,还可能有逻辑运算,所以Operator的抽象类应该规定两个抽象方法:evaluation和needArgus,每个operator实现自己的evaluation来实际执行运算规则,并返回一个Operand(父类),needArgs表示自己需要的参数格式,evaluation方法接受的就是当前的Operand 栈,这样就不用管每个Operand需要多少操作数了。evaluation可以跑出EvaluationException错误,表示执行逻辑发生问题,比如 1 / 0 的错误。


类图:

       这是类图,可以参考实现,有了类图,代码就不难了(不过这个问题中,代码实现起来还真会有点小难度)。



总结:

       用逆波兰表达式解析公式总体思路上不算太难。但是真正实现起来,因为用户输入的复杂性,所以对正则表达式的编写比较严格。完成中缀表达式的构建后,公式求值很简单。代码有时间再贴出来,因为一些原因,现在就不贴源代码了。不过思路大概就是上面的了。

        PS:有些实现中,对于公式的嵌套解析使用了递归的算法,这样能简化代码和逻辑。但是实际使用时容易产生效率问题,公式嵌套时完全可以改为非递归的实现。公式链就比较麻烦了,需要使用一个全局的公式管理器为公式规定执行顺序,这是最简单的方案。



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值