了解反向波兰表示法,作业作业?

时间:2010-04-27 16:11:04

标签: c programming-languages

我被要求在C中写一个简单的反向波兰表示法计算器作为家庭作业的一部分。我很难理解RPN。你能帮我理解反波兰表示法吗?此外,非常感谢任何有关如何处理此问题的提示。

4 个答案:

答案 0 :(得分:12)

Reverse Polish Notation是一种编写表达式的特定方法,首先写入值,然后是要执行的操作。例如,要添加数字3和4,您需要编写3 4 +

所以写一个你需要的RPN计算器

  • 接受输入的方法,例如从控制台
  • tokenizing输入的一种方式(对于你正在做的事情,打破空白就足够了)
  • 用于存储值(操作数)的stack(例如上面的3和4)
  • 操作词典

然后循环变为,实质上:

while (there's a token available) {
    token = get_the_token
    if (token is known operator) {
        get the number of values from stack this operation requires (usually two); fail if stack doesn't have enough
        perform operation on values
        push result on the stack
    }
    else if (token is valid value) {
        push it on the stack
    }
    else {
        show error: invalid input
    }
}
show result remaining on stack

你可以看到为什么RPN使编写计算器相当容易:你不必担心在它们运行的​​值之间有操作符,并且你不需要使用括号进行分组,就像使用更常见的{{{{{{ 3}}符号的形式。例如,我们用中缀表示法写(10 + (4 * 2)) / 9,我们在RPN中写10 4 2 * + 9 /。你的计算器将处理这样的令牌:

  • 10:这是一个值,将其推入堆栈
  • 4:这是一个值,将其推入堆栈
  • 2:这是一个值,将其推入堆栈
  • *:它是一个运算符,从堆栈中弹出2和4并将它们相乘(4 * 2);将结果(8)推入堆栈
  • +:它是一个运算符,从堆栈弹出8和10并添加它们(10 + 8);将结果(18)推入堆栈
  • 9:这是一个值,将其推入堆栈
  • /:它是一个操作符,从堆栈中弹出9和18并将它们分开(18 / 9);将结果(2)推到堆栈上(注意堆栈顶部的值 - 在这种情况下为9 - 是除数,其下的下一个值 - 18 - 是被除数)
  • 输入结束,显示堆栈上的值:2

答案 1 :(得分:4)

Reverse Polish Notation是数学表达式的一种表示形式,其中运算符遵循操作数。在评估RPN表达式时,每个二元运算符引用紧接在它之前的两个操作数 。以此RPN表达式为例:

5 4 3 + *

从左侧开始扫描表达式,直到找到第一个运算符+。此运算符具有操作数43(紧接在它之前的操作数),因此我们可以用结果7替换所有三个操作数。 (请注意,括号不是必需的,但我使用它们来帮助澄清含义)。

5 (4 3 +) * => 5 7 *

现在我们有了运算符*,以及两个操作数57(这实际上是4 + 3的结果)。我们将57相乘,整个表达式的计算结果为35

5 7 * => 35

这是评估任何RPN表达式的通用算法。


RPN表达式特别适合使用称为stack的数据结构的计算机进行评估。

堆栈是有序集合,其中一端被指定为“顶部”。项目始终添加到堆栈中或从顶部的堆栈中删除。这样,唯一要删除的项目始终是最近添加的项目。出于这个原因,堆栈有时被称为Last In,First Out(或LIFO),因为推入堆栈的最后一个元素位于顶部,因此将是第一个被删除的元素。

在C中,您可以实现一个包含两个变量的堆栈:一个数组(大到足以容纳您希望堆栈需要的最大元素数)和一个整数,它指示数组中的哪个索引当前是顶部。

堆栈非常适合评估RPN表达式,因为当遇到运算符时,它总是适用于最近遇到的操作数。因此,当您从左侧扫描表达式时,可以将操作数保存在堆栈中。再举一遍我们的例子:

5 4 3 + *

这里的第一件事是操作数(5),所以将它推入堆栈(最初是空的)。然后我们遇到4并将其推入堆栈。它成为新的顶级。然后我们对3执行相同操作。

5 4 3 <-- top
+ * // Remaining expression

接下来我们遇到+运算符。我们知道它适用于以前遇到的操作数,但我们在哪里找到它们?当然,在堆栈顶部!从堆栈中弹出34,然后将其添加到获取7。但该结果怎么办?好吧,它可能是另一个运算符的操作数,所以将它推回到堆栈上(就像我们在手动计算表达式时用操作符替换操作数和运算符一样):

5 7 <-- top
* // Remaining expression

现在我们看到*。再一次,最近遇到的操作数是堆栈中的两个顶级操作数。我们弹出它们并乘以得到35,然后将其推回堆栈。

35 <-- top
// No expression remaining

此时,我们已经到达表达式的末尾,堆栈中唯一的东西就是结果。我们完成了!您可以看到操作数堆栈如何“保存”遇到的第一个操作数,直到遇到相应的操作符,这可能位于表达式的另一端。

如果我们到达终点并发现堆栈上还剩下一个数字,那就会告诉我们表达式中有太多的操作数并且没有足够的操作符。另一方面,如果我们在某个时刻遇到一个运算符并且堆栈中的操作数少于两个,我们就会知道运算符太多而表达式中没有足够的操作数。

答案 2 :(得分:2)

答案 3 :(得分:0)

您可以在http://expressionoasis.vedantatree.com/

找到一个简单的实现