[英]Understanding Postfix-expression Evaluation in Java code using a stack
[英]expression evaluation using stack in java
我的程序正在使用像 12 + 3 * 45 这样的表达式。但是它不能像 12*4+(7/2) 这样的表达式工作。 请更正我的代码。我附上我的代码:
import java.util.Stack;
public class EvaluateString
{
public static int evaluate(String expression)
{
char[] tokens = expression.toCharArray();
// Stack for numbers: 'values'
Stack<Integer> values = new Stack<Integer>();
// Stack for Operators: 'ops'
Stack<Character> ops = new Stack<Character>();
for (int i = 0; i < tokens.length; i++)
{
// Current token is a whitespace, skip it
if (tokens[i] == ' ')
continue;
// Current token is a number, push it to stack for numbers
if (tokens[i] >= '0' && tokens[i] <= '9')
{
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// Current token is an opening brace, push it to 'ops'
else if (tokens[i] == '(')
ops.push(tokens[i]);
// Closing brace encountered, solve entire brace
else if (tokens[i] == ')')
{
while (ops.peek() != '(')
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
ops.pop();
}
// Current token is an operator.
else if (tokens[i] == '+' || tokens[i] == '-' ||
tokens[i] == '*' || tokens[i] == '/')
{
// While top of 'ops' has same or greater precedence to current
// token, which is an operator. Apply operator on top of 'ops'
// to top two elements in values stack
while (!ops.empty() && hasPrecedence(tokens[i], ops.peek()))
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Push current token to 'ops'.
ops.push(tokens[i]);
}
}
// Entire expression has been parsed at this point, apply remaining
// ops to remaining values
while (!ops.empty())
values.push(applyOp(ops.pop(), values.pop(), values.pop()));
// Top of 'values' contains result, return it
return values.pop();
}
// Returns true if 'op2' has higher or same precedence as 'op1',
// otherwise returns false.
public static boolean hasPrecedence(char op1, char op2)
{
if (op2 == '(' || op2 == ')')
return false;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-'))
return false;
else
return true;
}
// A utility method to apply an operator 'op' on operands 'a'
// and 'b'. Return the result.
public static int applyOp(char op, int b, int a)
{
switch (op)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
if (b == 0)
throw new
UnsupportedOperationException("Cannot divide by zero");
return a / b;
}
return 0;
}
// Driver method to test above methods
public static void main(String[] args)
{
System.out.println(EvaluateString.evaluate("10 + 2 * 6"));
}
}
让我们看一下解析数字的块:
for (int i = 0; i < tokens.length; i++) {
// ...
if (tokens[i] >= '0' && tokens[i] <= '9')
{
StringBuffer sbuf = new StringBuffer();
// There may be more than one digits in number
while (i < tokens.length && tokens[i] >= '0' && tokens[i] <= '9')
sbuf.append(tokens[i++]);
values.push(Integer.parseInt(sbuf.toString()));
}
// ...
}
让我们假设我们的标记是 {'1', '+', '2'} 并且您的初始i
值是 0。我们正在输入if
-body(作为tokens[0] == 1
),声明一个sbuf
变量和再次对i
进行完全相同的检查(但我们在if
-block 内进行与while
条件相同的检查)。 因此,我们将进入 while 循环,将tokens[0]
附加到sbuf
并增加我们的i
。 所以现在i
是 1 并指向+
,而 condition 是false
,我们将"1"
解析为 1 并将其添加到values
。 但是现在外部 for 循环的下一次迭代开始, i
值将是2
。 因此,我们完全错过了+
因为我们在 while 循环中增加了它的值,但没有以任何方式处理它。
现在让我们找到一种替代方法:
for (int i = 0; i < tokens.length; i++) {
// ...
if (tokens[i] >= '0' && tokens[i] <= '9') {
StringBuilder sb = new StringBuilder();
sb.append(tokens[i]);
// There may be more than one digits in number
while (i + 1 < tokens.length && tokens[i + 1] >= '0' && tokens[i + 1] <= '9') {
sb.append(tokens[++i]);
}
values.push(Integer.parseInt(sb.toString()));
}
// ...
}
这种方法在声明sb
后立即添加当前值(我将StringBuffer
更改为StringBuilder
因为不需要使用线程安全的StringBuffer
实现)。 接下来,我们将检查i
的下一个值而不增加。 如果它也是一个数字,我们将增加i
并将其附加到sb
。 否则i
不会发生任何变化,它仍将指向相同的值(在我们的例子中为 1)。 现在您的外部 for 循环将增加它,您将正确处理+
。
顺便说一句,如果您正在编写解析器,最好不仅返回values.pop()
还检查values.size() == 1
。 如果大小不是 1,则表达式要么不正确,要么未正确解析。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.