public class Calculate {
public static void main(String[] args) {
Stack<Symbol> ops = new Stack<>();
Stack<Double> vals = new Stack<>();
while (!StdIn.isEmpty()) {
String s = StdIn.readString();
if (s.equals("e")) {
break;
}
if (s.trim().equals(" ")) {
continue;
}
Operation o = Operation.fromSymbol(s);
if (o != null) {
ops.push(o);
continue;
}
Bound b = Bound.fromSymbol(s);
if (b != null) {
b.execute(ops, vals);
continue;
}
vals.push(Double.parseDouble(s));
}
System.out.println(vals.pop());
}
}
interface Symbol {
}
/**
* 边界符号,遇到之后做点什么
*
* @author yaoqiang
*/
enum Bound implements Symbol {
PREFIX("(") {
@Override
public void execute(Stack<Symbol> ops, Stack<Double> vals) {
ops.add(this);
}
},
SUFFIX(")") {
@Override
public void execute(Stack<Symbol> ops, Stack<Double> vals) {
List<Symbol> list = new ArrayList<>();
Symbol s = ops.pop();
do {
list.add(s);
s = ops.pop();
} while (s != Bound.PREFIX);
List<Double> val = new ArrayList<>();
for (int i = 0; i <= list.size(); i++) {
val.add(vals.pop());
}
Symbol[] arr = list.toArray(new Symbol[list.size()]);
Integer[] indexArr = new Integer[list.size()];
for (int i = 0; i < list.size(); i++) {
indexArr[i] = i;
}
for (int i = 1; i < list.size(); i++) {
Symbol temp = arr[i];
int sj = i;
// 数值越低,则优先级越高
// 这里需要注意一个问题,插入排序是稳定的,而这里 需要与稳定相反
// 由于取出是按照栈顺序的 所以原始索引 是左边的索引大于右边的索引
// 优先级越高,则数值越低,这样的 操作符 和 索引位置应该被推到前面。 虽然只操作索引,不过操作符也得同步,才能够进行后续的比较。
// 注意:核心问题,相等的操作符。如果操作符相同,则应该是 左边的优先级更高,而左边的索引更大。
// 所以 逻辑就变得有些混乱,即 按照 order 从低到高排序。
// 如果相等 ( 从 栈取出,索引顺序为 从 右到左 ),则应该 让索引更大的排前面。即 即使相同,也要交换,让大索引优先。这与稳定刚好相反
for (int j = i; j > 0 && ((Operation) arr[j - 1]).getOrder() >= ((Operation) temp).getOrder(); j--) {
arr[j] = arr [j-1];
indexArr[j] = indexArr[j - 1];
sj = j - 1;
}
if (sj != i) {
indexArr[sj] = i;
arr[sj] = temp;
}
}
// ( 1 + 2 * 3 + ( 2 + 3 * 4 ) ) e
// 当 优先级高的被合并的时候,不得不 合并结果到val中,比如 2 , 3 合并为 2,所以原来的索引 i ,i + 1 也就失效
// 虽然失效,不过依然又规律可循,记录操作索引,如果 运行过的索引 存在 比 当前索引更小的,则需要减去这些数量(栈,从后到前,越左的索引,越大)
// 得到的即 合并后的索引数量。
// list 存储的是 操作符的原始位置,由于操作符没有做任何合并,所以索引不需要改变,依然按照原来的索引搜索。
Set<Integer> set = new HashSet<>();
for (Integer idx : indexArr) {
Integer finalIdx = idx;
idx = idx - Long.valueOf(set.stream().filter(i->i< finalIdx).count()).intValue();
Double d = ((Operation) list.get(finalIdx)).execute(val.get(idx + 1), val.get(idx));
set.add(idx);
val.remove(idx.intValue());
val.remove(idx.intValue());
val.add(idx, d);
}
vals.push(val.get(0));
}
};
private final String symbol;
private static final EnumSet<Bound> all;
static {
all = EnumSet.allOf(Bound.class);
}
public static Bound fromSymbol(String s) {
return all.stream().filter(o -> o.symbol.equals(s)).findFirst().orElse(null);
}
Bound(String symbol) {
this.symbol = symbol;
}
public abstract void execute(Stack<Symbol> ops, Stack<Double> vals);
}
/**
* 操作符
*
* @author root
*/
enum Operation implements Symbol {
PLUS("+", 1) {
@Override
public double execute(double one, double two) {
return one + two;
}
},
MINUS("-", 1) {
@Override
public double execute(double one, double two) {
return one - two;
}
},
MULTIPLY("*", 0) {
@Override
public double execute(double one, double two) {
return one * two;
}
},
DIVIDE("/", 0) {
@Override
public double execute(double one, double two) {
return one / two;
}
};
private final String symbol;
private final Integer order;
private static final EnumSet<Operation> all;
static {
all = EnumSet.allOf(Operation.class);
}
public static Operation fromSymbol(String s) {
return all.stream().filter(o -> o.symbol.equals(s)).findFirst().orElse(null);
}
Operation(String symbol, Integer order) {
this.symbol = symbol;
this.order = order;
}
public Integer getOrder() {
return this.order;
}
public abstract double execute(double one, double two);
}
<dependency>
<groupId>edu.princeton.cs</groupId>
<artifactId>algs4</artifactId>
<version>1.0.3</version>
</dependency>
示例输入:( 1 + 2 * 3 + ( 2 + 3 * 4 ) ) e