我被要求在C中写一个简单的反向波兰表示法计算器作为家庭作业的一部分。我很难理解RPN。你能帮我理解反波兰表示法吗?此外,非常感谢任何有关如何处理此问题的提示。
答案 0 :(得分:12)
Reverse Polish Notation是一种编写表达式的特定方法,首先写入值,然后是要执行的操作。例如,要添加数字3和4,您需要编写3 4 +
。
所以写一个你需要的RPN计算器
然后循环变为,实质上:
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 + *
从左侧开始扫描表达式,直到找到第一个运算符+
。此运算符具有操作数4
和3
(紧接在它之前的操作数),因此我们可以用结果7
替换所有三个操作数。 (请注意,括号不是必需的,但我使用它们来帮助澄清含义)。
5 (4 3 +) * => 5 7 *
现在我们有了运算符*
,以及两个操作数5
和7
(这实际上是4 + 3的结果)。我们将5
和7
相乘,整个表达式的计算结果为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
接下来我们遇到+
运算符。我们知道它适用于以前遇到的操作数,但我们在哪里找到它们?当然,在堆栈顶部!从堆栈中弹出3
和4
,然后将其添加到获取7
。但该结果怎么办?好吧,它可能是另一个运算符的操作数,所以将它推回到堆栈上(就像我们在手动计算表达式时用操作符替换操作数和运算符一样):
5 7 <-- top
* // Remaining expression
现在我们看到*
。再一次,最近遇到的操作数是堆栈中的两个顶级操作数。我们弹出它们并乘以得到35
,然后将其推回堆栈。
35 <-- top
// No expression remaining
此时,我们已经到达表达式的末尾,堆栈中唯一的东西就是结果。我们完成了!您可以看到操作数堆栈如何“保存”遇到的第一个操作数,直到遇到相应的操作符,这可能位于表达式的另一端。
如果我们到达终点并发现堆栈上还剩下一个数字,那就会告诉我们表达式中有太多的操作数并且没有足够的操作符。另一方面,如果我们在某个时刻遇到一个运算符并且堆栈中的操作数少于两个,我们就会知道运算符太多而表达式中没有足够的操作数。
答案 2 :(得分:2)
答案 3 :(得分:0)