輸入:每行輸入一個(gè)表達(dá)式,運(yùn)算符包含+-*/和括號(hào),運(yùn)算符和數(shù)字用空格隔開(kāi)。如果需要擴(kuò)充,其余運(yùn)算符也可以直接再枚舉類中加。
輸入 : 1 * 2 + 3
輸出 : 5
輸入 2 * ( 2 + 3 )
輸出 : 10
本人覺(jué)得自己做得比較好的地方是用枚舉表示運(yùn)算符,同時(shí)對(duì)不合法的表達(dá)式做了異常處理。
代碼如下:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Scanner;
import java.util.Stack;
/**
* Created by lxhao on 17-6-24.
*/
public class Test {
public static void main(String args[]) {
Scanner in = getScanner("input.txt");
while (in.hasNext()) {
String[] expression = in.nextLine().split("\\s");
System.out.println(Claculator.compute(expression));
}
}
//從輸入流讀取輸入數(shù)據(jù)
public static Scanner getScanner(InputStream is) {
return new Scanner(is);
}
//從文件讀取輸入數(shù)據(jù)
public static Scanner getScanner(String fileName) {
try {
return getScanner(new FileInputStream(fileName));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 表達(dá)式求值
* <p>
* 棧的規(guī)則是先進(jìn)后出。利用壓棧的思想來(lái)計(jì)算四則運(yùn)算表達(dá)式是這樣的:我們給定兩個(gè)棧,
* 一個(gè)用來(lái)存放數(shù)字、一個(gè)用來(lái)存放對(duì)應(yīng)的操作符。假定我們有一個(gè)給定的四則運(yùn)算表達(dá)式a+b+c/d*(e+f)-d*a,
* 那我們先把這個(gè)表達(dá)式拆分成一個(gè)個(gè)的數(shù)字或者是運(yùn)算符、或者就是括號(hào)了。
* 然后我們從左至右遍歷每一個(gè)元素,遍歷過(guò)程中遵循步驟和原則如下:
* (1)遇到數(shù)字則直接壓到數(shù)字棧頂。
* (2)遇到運(yùn)算符(+-/*)時(shí),若操作符棧為空,則直接放到操作符棧頂,否則,見(jiàn)(3)。
* (3)若操作符棧頂元素的優(yōu)先級(jí)比當(dāng)前運(yùn)算符的優(yōu)先級(jí)小,則直接壓入棧頂,否則執(zhí)行步驟(4)。
* (4)彈出數(shù)字棧頂?shù)膬蓚€(gè)數(shù)字并彈出操作符棧頂?shù)倪\(yùn)算符進(jìn)行運(yùn)算,把運(yùn)算結(jié)果壓入數(shù)字棧頂,重復(fù)(2)和(3)直到當(dāng)前運(yùn)算符被壓入操作符棧頂。
* (5)遇到左括號(hào)“(”時(shí)則直接壓入操作符棧頂。
* (6)遇到右括號(hào)“)”時(shí)則依次彈出操作符棧頂?shù)倪\(yùn)算符運(yùn)算數(shù)字棧的最頂上兩個(gè)數(shù)字,直到彈出的操作符為左括號(hào)。
* <p>
* <p>
* http://elim.iteye.com/blog/1981197
*/
class Claculator {
public static double compute(String[] expression) {
//操作數(shù)棧
Stack<Double> numberStack = new Stack<>();
//表達(dá)式棧
Stack<Operator> operatorStack = new Stack<>();
for (String s : expression) {
//數(shù)字直接入棧
if (Operator.getOperator(s) == Operator.OTHER) {
numberStack.push(Double.parseDouble(s));
continue;
}
Operator operator = Operator.getOperator(s);
//棧為空或者遇到左括號(hào)直接入棧
if (operatorStack.isEmpty() || operator == Operator.LEFT_BRACKET) {
operatorStack.push(operator);
continue;
}
//遇到右括號(hào)則一直計(jì)算到左括號(hào)
if (operator == Operator.RIGHT_BRACKET) {
while (operatorStack.peek() != Operator.LEFT_BRACKET && numberStack.size() >= 2) {
//因?yàn)楹竺娴臄?shù)會(huì)先彈出來(lái),除法和減法是區(qū)分先后順序的(比如1 / 2不能算成2 / 1)
double n1 = numberStack.pop();
double resTmp = operatorStack.pop().compute(numberStack.pop(), n1);
numberStack.push(resTmp);
}
//不合法的表達(dá)式
if (operatorStack.pop() != Operator.LEFT_BRACKET) {
throw new IllegalArgumentException();
}
continue;
}
if (operator.getPriority() <= operatorStack.peek().getPriority()) {
//不合法的表達(dá)式
if (numberStack.size() < 2) {
throw new IllegalArgumentException();
}
while (operatorStack.size() > 0 && numberStack.size() >= 2 && operator.getPriority() <= operatorStack.peek().getPriority()) {
//彈出運(yùn)算符和兩個(gè)數(shù)組進(jìn)行計(jì)算
double n1 = numberStack.pop();
double resTmp = operatorStack.pop().compute(numberStack.pop(), n1);
numberStack.push(resTmp);
}
operatorStack.push(operator);
} else {
//當(dāng)前運(yùn)算符的優(yōu)先級(jí)比較高
operatorStack.push(operator);
}
}
while (operatorStack.size() > 0 && numberStack.size() >= 2) {
double n1 = numberStack.pop();
double resTmp = operatorStack.pop().compute(numberStack.pop(), n1);
numberStack.push(resTmp);
}
if (numberStack.size() == 1 && operatorStack.isEmpty()) {
return numberStack.pop();
}
//不合法的表達(dá)式
throw new IllegalArgumentException();
}
}
/**
* 運(yùn)算符
*/
enum Operator {
PLUS("+", 1) {
@Override
public double compute(double num1, double num2) {
return num1 + num2;
}
},
MINUS("-", 1) {
@Override
public double compute(double num1, double num2) {
return num1 - num2;
}
},
MULTIPLY("*", 2) {
@Override
public double compute(double num1, double num2) {
return num1 * num2;
}
},
DIVIDE("/", 2) {
@Override
public double compute(double num1, double num2) {
return num1 / num2;
}
},
REMAINDER("%", 2) {
@Override
public double compute(double num1, double num2) {
return num1 % num2;
}
},
EXPONENTIATION("^", 3) {
@Override
public double compute(double num1, double num2) {
return Math.pow(num1, num2);
}
},
INTEGER_DIVISION("http://", 2) {
@Override
public double compute(double num1, double num2) {
return Math.floor(num1 / num2);
}
},
RIGHT_BRACKET(")", 0) {
@Override
public double compute(double num1, double num2) {
throw new UnsupportedOperationException();
}
},
LEFT_BRACKET("(", 0) {
@Override
public double compute(double num1, double num2) {
throw new UnsupportedOperationException();
}
},
OTHER("", 0) {
@Override
public double compute(double num1, double num2) {
return 0;
}
};
private String value;
private int priority;
private Operator(String value, int priority) {
this.value = value;
this.priority = priority;
}
public static Operator getOperator(String value) {
for (Operator operator : Operator.values()) {
if (operator.value.equals(value)) {
return operator;
}
}
return OTHER;
}
public int getPriority() {
return priority;
}
public abstract double compute(double num1, double num2);
}
input.txt的測(cè)試數(shù)據(jù):
2 + 8 - 9 * ( 12 / 6 / 2 / 2 ) + 2 * 2 + 2 ^ 2 + 2 + 8 - 9 * ( 12 / 6 ) + 2 * 2 + 2 ^ 2
2 + 3 * 3 * 3 + 3 * 3 * 3
2 + 2 + 3 * 9
2 - 18 - 19
1 + 7 ^ 2