为什么postfix(rpn)符号比前缀更常用?

时间:2015-06-22 08:08:59

标签: algorithm calculator postfix-notation polish-notation

使用我的意思是它在许多计算器中使用,如HP35-

我的猜测(和混淆)是 -

  1. postfix实际上是更高效的内存 - (SO post comments here)。 (混淆 - 两者的评估算法与堆栈类似)
  2. 当时计算器中的键盘输入类型(混淆 - 这应该不重要,因为它只取决于首先或最后给出的运算符的顺序)
  3. 可以问这个问题的另一个方法是后缀表示法优于前缀的优点是什么? 谁能开导我?

5 个答案:

答案 0 :(得分:5)

一方面,实施评估更容易。

使用前缀,如果您按下运算符,然后是其操作数,则需要具有运算符何时具有其所有操作数的前向知识。基本上你需要跟踪你推动的操作符何时具有所有操作数,以便你可以展开堆栈并进行评估。

由于复杂表达式可能最终会出现堆栈中的许多运算符,因此您需要具有可以处理此问题的数据结构。

例如,这个表达式:- + 10 20 + 30 40将同时在堆栈上有一个-和一个+,对于每个表达式,您需要知道是否有可用的操作数

使用后缀,当您按下运算符时,操作数(应该)已经在堆栈上,只需弹出操作数并进行求值。您只需要一个可以处理操作数的堆栈,而不需要其他数据结构。

答案 1 :(得分:2)

基本上,因为如果你在 postfix 中编写表达式,你可以只使用 Stack 评估该表达式:

  1. 阅读表达式的下一个元素

  2. 如果是操作数,请进入Stack,

  3. 否则从操作所需的堆栈操作数中读取,&将结果推入Stack。

  4. 如果不是表达式的结尾,请转到1.

  5. 示例

    expression = 1 2 + 3 4 + *
    stack = [  ]
    
    Read 1, 1 is Operand, Push 1
    [ 1 ]
    
    Read 2, 2 is Operand, Push 2
    [ 1 2 ]
    
    Read +, + is Operation, Pop two Operands 1 2
    Evaluate 1 + 2 = 3, Push 3
    [ 3 ]
    
    Read 3, 3 is Operand, Push 3
    [ 3 3 ]
    
    Read 4, 4 is Operand, Push 4
    [ 3 3 4 ]
    
    Read +, + is Operation, Pop two Operands 3 4
    Evaluate 3 + 4 = 7, Push 7
    [ 3 7 ]
    
    Read *, * is Operation, Pop two Operands 3 7
    Evaluate 3 * 7 = 21, Push 21
    [ 21 ]
    

答案 2 :(得分:2)

如果您喜欢人类阅读顺序以匹配机器的基于堆栈的评估顺序,那么postfix是一个不错的选择。

也就是说,假设你从左到右阅读,并非每个人都这样做(例如希伯来语,阿拉伯语......)。并假设您的机器使用堆栈进行评估,而这并非全部(例如,术语重写 - 请参阅Joy)。

另一方面,当机器评估“从前到后/从下到上”时,人类偏好前缀没有任何问题。如果关注是作为令牌到达,序列化也可以反转。工具辅助可以在前缀表示法中更好地工作(首先知道函数/单词可以帮助确定范围有效参数),但是你总是可以从右到左输入

这只是一个我相信的惯例......

答案 3 :(得分:2)

前缀表示法可能更常用于...在数学中,在F(x,y)等表达式中。这是一个非常古老的惯例,但与许多旧系统(英尺和英寸,信纸)一样,与我们使用设计更加精心的系统时相比,它有缺点。

几乎每一年大学数学教科书都要浪费一页,至少解释f(g(x))意味着我们首先应用g然后f。按阅读顺序执行此操作更有意义:x.f.g表示我们首先应用f。然后,如果我们想在"之后应用h"我们只是说x.f.g.h

作为一个例子,考虑一下我最近必须处理的3d旋转问题。我们想根据XYZ惯例旋转矢量。在后缀中,操作为vec.rotx(phi).roty(theta).rotz(psi)。使用前缀时,我们必须重载*(),然后反转操作的顺序,例如rotz*roty*rotx*vec。当你想要考虑更大的问题时,不得不一直考虑这一点,这是容易出错和烦人的。

例如,我在其他人的代码中看到了类似rotx*roty*rotz*vec的内容,我不知道这是一个错误还是一个不寻常的ZYX轮换约定。我还是不知道。该程序有效,因此内部是自洽的,但在这种情况下,前缀表示法很难维护。

前缀表示法的另一个问题是,当我们(或计算机)解析表达式f(g(h(x)))时,我们必须在我们的内存中(或在堆栈中)保留f,然后g ,然后h,然后确定我们可以将h应用于x,然后我们可以将g应用于结果,然后f应用于结果。与x.f.g.h相比,内存中的内容太多了。在某些时候(人类比计算机早得多)我们将耗尽内存。以这种方式失败并不常见,但是当x.f.g.h不需要短期记忆时,为什么要打开门呢?这就像递归和循环之间的区别。

还有一件事:f(g(h(x)))有很多括号,它开始看起来像Lisp。对于运算符优先级,后缀表示法是明确的。

一些数学家(特别是Nathan Jacobson)试图改变惯例,因为后缀在非交换代数中更容易使用,其中顺序真的很重要,但没什么用。但是既然我们有机会在计算机上做更好的事情,我们应该抓住机会。

答案 4 :(得分:0)

两种表示法的离线评估在理论机上都是相同的

(急切的评估策略)仅使用一个堆栈进行评估(不将运算符放在堆栈中)

可以通过评估前缀符号 right-to-left来完成。

- 7 + 2 3
# evaluate + 2 3
- 7 5
# evaluate - 7 5
2

与评估后缀符号 left-to-right相同。

7 2 3 + -
# put 7 on stack
7 2 3 + -
# evaluate 2 3 +
7 5 -
# evaluate 7 5 -
2

(优化的短路策略)使用两个堆栈进行评估(一个用于运算符,一个用于操作数)

可以通过评估前缀符号 left-to-right来完成。

|| 1 < 2 3
# put || in instruction stack, 1 in operand stack or keep the pair in stack
instruction-stack: or
operand-stack: 1
< 2 3
# push < 2 3 in stack
instruction-stack: or, less_than
operand-stack: 1, 2, 3
# evaluate < 2 3 as 1
instruction-stack: or
operand-stack: 1, 1
# evaluate || 1 1 as 1
operand-stack:1

请注意,我们可以轻松地对此处的boolean表达式进行短路优化()(与之前的评估顺序相比)。

|| 1 < 2 3
# put || in instruction stack, 1 in operand stack or keep the pair in stack
instruction-stack: or
operand-stack: 1
< 2 3
# Is it possible to evaluate `|| 1` without evaluating the rest ? Yes !!
# skip < 2 3 and put place-holder 0
instruction-stack: or
operand-stack: 1 0
# evaluate || 1 0 as 1
operand-stack: 1

与评估后缀符号 right-to-left相同。

(优化的短路策略)使用带元组的堆栈进行评估(与上面相同)

可以通过评估前缀符号 left-to-right来完成。

|| 1 < 2 3
# put || 1 in tuple-stack
stack tuple[or,1,unknown]
< 2 3
# We do not need to compute < 2 3
stack tuple[or,1,unknown]
# evaluate || 1 unknown as 1
1

与评估后缀符号 right-to-left相同。

当人们从左到右输入数据时,在计算器中进行在线评估

在计算器中放置数字时,可以立即计算后缀符号 2 3 +,而无需了解人类将要放置的符号。前缀表示法与之相反,因为当我们拥有- 7 +时,我们什么都不做,直到我们得到- 7 + 2 3之类的东西。

当人们从右到左输入数据时,在计算器中进行在线评估

现在前缀符号可以立即求值+ 2 3,而后缀符号具有3 + -时,则等待进一步的输入。 / p>

请参阅@AshleyF,请注意,阿拉伯语是从右向左书写的,而英语是从左向书写的书写!

我想 little-endian big-endian 与此前缀/后缀表示法有关。

最后一条评论是,反向抛光符号得到Dijkstra的大力支持(他是短路优化的坚决反对者,被认为是反向抛光符号的发明者)。您可以选择是否支持他的意见(我不支持)。