帮我堆栈溢出,你是我唯一的希望。我一直在努力制作一个简单的计算器,最后我已经开始工作了!问题是只评估表达式。例如:4 * 5将给出20.0。 (真棒!)
每当我给它一个更复杂的表达式如4 *(2 + 3)时,程序因EmptyStackException而崩溃。我理解异常,但是当我用脑子和一张纸手动完成代码时,我无法重新思考这个问题。
任何人都可以弄清楚它崩溃的原因吗?这是完整的代码。我用一些大胆的全文字标记了代码崩溃的地方。 (即程序崩溃)
/**
* Human
* Project 3: SUPER-DUPER JAVA CALCULATOR
*/
import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator {
public static class SyntaxErrorException extends Exception {
/**
* Construct a SyntaxErrorException with the specified message.
*
* @param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/**
* This is the stack of operands:
* i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/**
* This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/**
* These are the possible operators
*/
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/**
* This is an ArrayList of all the discrete
* things (operators/operands) making up an input.
* This is really just getting rid of the spaces,
* and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix) {
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length() - 1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length() - 1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c) != -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(":
numLP++;
break;
case "[":
numLB++;
break;
case "{":
numLBr++;
break;
case ")":
numRP++;
break;
case "]":
numRB++;
break;
case "}":
numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(":
doop++;
break;
case "[":
scoop++;
break;
case "{":
foop++;
break;
case ")":
doop--;
break;
case "]":
scoop--;
break;
case "}":
foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size() - 1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**
* Method to process operators
*
* @param op The operator
* @throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op == "(" || op == "[" || op == "{") {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
operatorStack.push(op);
} else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp == "(" || topOp == "[" || topOp == "{") {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if (op != ")" || op != "]" || op != "}") {
operatorStack.push(op);
}
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+":
operandStack.push(l + r);
break;
case "-":
operandStack.push(l - r);
break;
case "*":
operandStack.push(l * r);
break;
case "/":
operandStack.push(l / r);
break;
case "%":
operandStack.push(l % r);
break;
case "^":
operandStack.push(Math.pow(l, r));
break;
default:
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
do {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (EmptyStackException e) {
System.out.println("Make sure you only put in operators and operands.");
}
} while (true);
}
}
堆栈追踪:
java.util.EmptyStackException at
java.util.Stack.peek(Stack.java:102) at
java.util.Stack.pop(Stack.java:84) at
InfixEvaluator.processOperator(InfixEvaluator.java:177) at
InfixEvaluator.infixCalculator(InfixEvaluator.java:225) at
InfixEvaluator.main(InfixEvaluator.java:276)
答案 0 :(得分:2)
当堆栈为空时,您的错误来自pop
堆栈中的元素。因此名称为EmptyStackException
。
我注意到在你的循环中你会说while(!operatorStack.empty())
之类的东西但是在while循环中你会弹出2个或者有时会从堆栈中弹出3个元素。如果你想从数组中弹出更多的元素而不是你应该在while循环中测试的元素。
因此,如果您关闭2个元素,请执行while (operatorStack.size() > 2 )
。我编辑了你的代码,改变你所有的while循环是正确的,它适用于这些输入
(2+3)
和
(2+3)+5
这是我做的:
str1 == str2
到str1.equals(str2)
的大量地方的字符串比较。你应该看看How do I compare strings in Java?,看看为什么我这样做。System.out.println
语句中添加以调试您的应用程序。我把它们留在了,所以你可以看到输出并亲自检查。您应该查看并查看我将来做了哪些工作来帮助您进行调试。 import java.util.*;
import java.util.Stack;
import java.lang.String;
import java.util.ArrayList;
import java.lang.StringBuilder;
import java.util.HashSet;
import java.lang.Exception;
import java.lang.Math;
public class InfixEvaluator
{
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
@param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
// + - / * % ^ ( ) [ ] { }
private static final int[] PRECEDENCE = {1, 1, 2, 2, 3, 3, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
/**
* TODO: write this
* @param postfix
* @return
*/
public static ArrayList inputCleaner(String postfix){
StringBuilder sb = new StringBuilder();
String noSpaces = postfix.replace(" ", "");
try {
for (int i = 0; i < noSpaces.length(); i++) {
char c = noSpaces.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
sb.append(c);
if (i == noSpaces.length()-1) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
} else if (c == '.') {
for (int j = 0; j < sb.length(); j++) {
if (sb.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == sb.length() - 1) {
sb.append(c);
j = (sb.length() + 1);
}
}
if (sb.length() == 0) {
sb.append(c);
}
if (i == noSpaces.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (sb.length() != 0) {
input.add(sb.toString());
sb.delete(0, sb.length());
}
sb.append(c);
input.add(sb.toString());
sb.delete(0, sb.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
switch (input.get(f)) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* @param op The operator
* @throws SyntaxErrorException
* @throws EmptyStackException
*/
private static void processOperator(String op) throws SyntaxErrorException {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
topOp = op;
operatorStack.push(op);
} else {
System.out.println(operatorStack);
System.out.println(operandStack);
System.out.println("--------------");
//Pop all stacked operators with equal
// or higher precedence than op.
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
if(op.equals("(") || op.equals("[") || op.equals("{")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
if(!op.equals(")") || !op.equals("}") || !op.equals("}")) {
operatorStack.push(op);
}
}
}
}
/**
* TODO: write this
* @param expressions
* @return
* @throws SyntaxErrorException
*/
public static String infixCalculator(ArrayList<String> expressions) throws SyntaxErrorException {
for (String expression : expressions) {
if (OPERATORS.indexOf(expression) == -1) {
operandStack.push(Double.parseDouble(expression));
} else {
processOperator(expression);
}
}
while (operandStack.size() >= 2 && !operatorStack.isEmpty()) {
System.out.println("--------------");
System.out.println(operandStack);
System.out.println(operatorStack);
double r = operandStack.pop();
double l = operandStack.pop();
String work = getNextNonBracerOperator();
System.out.println("L:" + l + " R:" + r + " W:" + work);
doOperandWork(work, l, r);
}
if(operandStack.isEmpty())
return null;
return String.valueOf(operandStack.pop());
}
/**
* goes through the stack and pops off all non operatable operations until it gets to one that is in the NONBRACES String
* @return The next operatable string
*/
private static String getNextNonBracerOperator() {
String work = "\0"; // \0 is null,
while(!operatorStack.isEmpty() && NONBRACES.indexOf(work) == -1)
work = operatorStack.pop();
return work;
}
/**
*
* @param work The operator you want to work. This really should be a character but its still a string
* @param l Left side number
* @param r Right side number
* @throws SyntaxErrorException If the operator could not be found
*/
private static void doOperandWork(String work, double l, double r) throws SyntaxErrorException {
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default:
throw new SyntaxErrorException("Invalid operand " + work);
}
}
/**
* @param op The operator
* @return the precedence
*/
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
public static void main(String[] args) {
try {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
//System.out.println("Please insert an argument: ");
//String g = f.nextLine();
//String g = "(1+1)^(3+1)";
String g = "(1+3)*3^2+2*4-1";
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
test.clear();
} catch (SyntaxErrorException e) {
System.out.println("Make sure you only put in operators and operands.");
e.printStackTrace();
}
}
}
答案 1 :(得分:0)
您正在尝试将字符串与==
进行比较。而是使用String.equals(String)
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
...
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
...
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
如果您跟踪代码,您将看到您尝试使用"("
作为运算符
在检查之前,您已经将")"
推回到堆栈中。你应该进行检查。
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
最终守则
import java.util.*;
public class InfixEvaluator
{
public static void main(String[] args) {
ArrayList test = new ArrayList();
Scanner f = new Scanner(System.in);
System.out.println("Please insert an argument: \n");
String g = f.nextLine();
test = inputCleaner(g);
for (int z = 0; z < test.size(); z++) {
System.out.println(test.get(z));
}
System.out.println(infixCalculator(test));
}
public static class SyntaxErrorException extends Exception {
/** Construct a SyntaxErrorException with the specified message.
@param message The message
*/
SyntaxErrorException(String message) {
super(message);
}
}
/** This is the stack of operands:
i.e. (doubles/parentheses/brackets/curly braces)
*/
private static Stack<Double> operandStack = new Stack<Double>();
/** This is the operator stack
* i.e. (+-/*%^)
*/
private static Stack<String> operatorStack = new Stack<String>();
/** These are the possible operators */
private static final String OPERATORS = "+-/*%^()[]{}";
private static final String BRACES = "()[]{}";
private static final String NONBRACES = "+-/*%^";
private static final int[] PRECEDENCE = {1, 1, 2, 2, 2, -1, -1, -1, -1, -1, -1};
/** This is an ArrayList of all the discrete
things (operators/operands) making up an input.
This is really just getting rid of the spaces,
and dividing up the "stuff" into manageable pieces.
*/
static ArrayList<String> input = new ArrayList<String>();
public static ArrayList inputCleaner(String postfix){
StringBuilder poop = new StringBuilder();
String doody = postfix.replace(" ", "");
try {
for (int i = 0; i < doody.length(); i++) {
char c = doody.charAt(i);
boolean isNum = (c >= '0' && c <= '9');
if (isNum) {
poop.append(c);
if (i == doody.length()-1) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
} else if (c == '.') {
for (int j = 0; j < poop.length(); j++) {
if (poop.charAt(j) == '.') {
throw new SyntaxErrorException("You can't have two decimals in a number.");
} else if (j == poop.length() - 1) {
poop.append(c);
j = (poop.length() + 1);
}
}
if (poop.length() == 0) {
poop.append(c);
}
if (i == doody.length()-1) {
throw new SyntaxErrorException("You can't end your equation with a decimal!");
}
} else if (OPERATORS.indexOf(c)!= -1) {
if (poop.length() != 0) {
input.add(poop.toString());
poop.delete(0, poop.length());
}
poop.append(c);
input.add(poop.toString());
poop.delete(0, poop.length());
} else {
throw new SyntaxErrorException("Make sure your input only contains numbers, operators, or parantheses/brackets/braces.");
}
}
int numLP = 0;
int numRP = 0;
int numLB = 0;
int numRB = 0;
int numLBr = 0;
int numRBr = 0;
for (int f = 0; f < input.size(); f++) {
String trololol = input.get(f);
switch (trololol) {
case "(": numLP++;
break;
case "[": numLB++;
break;
case "{": numLBr++;
break;
case ")": numRP++;
break;
case "]": numRB++;
break;
case "}": numRBr++;
break;
default: //do nothing
break;
}
}
if (numLP != numRP || numLB != numRB || numLBr != numRBr) {
throw new SyntaxErrorException("The number of brackets, braces, or parentheses don't match up!");
}
int doop = 0;
int scoop = 0;
int foop = 0;
for (int f = 0; f < input.size(); f++) {
String awesome = input.get(f);
switch (awesome) {
case "(": doop++;
break;
case "[": scoop++;
break;
case "{": foop++;
break;
case ")": doop--;
break;
case "]": scoop--;
break;
case "}": foop--;
break;
default: //do nothing
break;
}
if (doop < 0 || scoop < 0 || foop < 0) {
throw new SyntaxErrorException("The order of your parentheses, brackets, or braces is off.\nMake sure you open a set of parenthesis/brackets/braces before you close them.");
}
}
if (NONBRACES.indexOf(input.get(input.size()-1)) != -1) {
throw new SyntaxErrorException("The input can't end in an operator");
}
return input;
} catch (SyntaxErrorException ex) {
System.out.println(ex);
return input;
}
}
/**Method to process operators
* @param op The operator
* @throws EmptyStackException
*/
private static void processOperator(String op) {
if (operatorStack.empty() || op.equals("(") || op.equals("[") || op.equals("{")) {
operatorStack.push(op);
} else {
//peek the operator stack and
//let topOp be the top operator.
String topOp = operatorStack.peek();
if (precedence(op) > precedence(topOp)) {
if(!op.equals(")") || !op.equals("]") || !op.equals("}")) {
operatorStack.push(op);
}
}
else {
//Pop all stacked operators with equal
// or higher precedence than op.
while (!operatorStack.empty() && precedence(op) <= precedence(topOp)) {
double r = operandStack.pop();
double l = operandStack.pop(); //***THE PROGRAM CRASHES HERE***
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
if (topOp.equals("(") || topOp.equals("[") || topOp.equals("(")) {
//matching '(' popped - exit loop.
operandStack.push(l);
operandStack.push(r);
break;
}
if (!operatorStack.empty()) {
//reset topOp
topOp = operatorStack.peek();
}
}
//assert: Operator stack is empty or
// current operator precedence > top of stack operator precedence.
}
}
}
public static String infixCalculator(ArrayList<String> puke) {
int p;
for (p = 0; p < puke.size(); p++) {
if (OPERATORS.indexOf(puke.get(p)) == -1) {
double herp = Double.parseDouble(puke.get(p));
operandStack.push(herp);
} else {
processOperator(puke.get(p));
}
}
if (p == puke.size()) {
while (!operatorStack.empty()) {
double r = operandStack.pop();
double l = operandStack.pop();
String work = operatorStack.pop();
switch (work) {
case "+": operandStack.push(l+r);
break;
case "-": operandStack.push(l-r);
break;
case "*": operandStack.push(l*r);
break;
case "/": operandStack.push(l/r);
break;
case "%": operandStack.push(l%r);
break;
case "^": operandStack.push(Math.pow(l, r));
break;
default: //do nothing, but this should never happen
break;
}
}
}
return String.valueOf(operandStack.pop());
}
private static int precedence(String op) {
return PRECEDENCE[OPERATORS.indexOf(op)];
}
}