高级农民
- 积分
- 2721
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2017-6-18
- 最后登录
- 1970-1-1
|
这边有一份支持“自定义操作符”的代码,LZ可以参考学习一下...
第13到22行的代码写出来是可以impress住面试官的,基本上所有Calculator的变形题都可以通过改这几行处理(如果要处理浮点类型则要稍微改一下nextNumber()函数)。
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Stack;
- public class Main {
- public static void main(String[] args) {
- Calculator calc = new Calculator();
- // 中间的数字是优先级(precedence),数字越小优先级越高
- // 这里限定二元运算符是left associative,一元运算符是right associative
- calc.registerOperation("+", 500, (a, b) -> a + b);
- calc.registerOperation("-", 500, (a, b) -> a - b);
- calc.registerOperation("*", 400, (a, b) -> a * b);
- calc.registerOperation("/", 400, (a, b) -> a / b);
- calc.registerOperation("**", 200, (a, b) -> (int) Math.pow(a, b));
- calc.registerOperation("-", 100, (a) -> -a);
- calc.registerFunction("abs", (int ...a) -> Math.abs(a[0]));
- calc.registerFunction("min", (int ...a) -> Math.min(a[0], a[1]));
- calc.registerFunction("max", (int ...a) -> Math.max(a[0], a[1]));
- System.out.println(calc.evaluate("1 + 2 * 3 ** abs(6 - 3 * 3) + (-8) / (-2)"));
- System.out.println(calc.evaluate("min(-3 * 2, -4) * max(5, 6)"));
- }
- }
- /******************************************************************************
- 样例:使用下面的Solution类可以通过LeetCode 224
- class Solution {
- private static Calculator calc = new Calculator();
- static {
- calc.registerOperation("+", 500, (a, b) -> a + b);
- calc.registerOperation("-", 500, (a, b) -> a - b);
- calc.registerOperation("-", 100, (a) -> -a);
- }
- public int calculate(String s) {
- return calc.evaluate(s);
- }
- }
- ******************************************************************************/
- /******************************************************************************
- 样例:使用下面的Solution类可以通过LeetCode 227
- class Solution {
- private static Calculator calc = new Calculator();
- static {
- calc.registerOperation("+", 500, (a, b) -> a + b);
- calc.registerOperation("-", 500, (a, b) -> a - b);
- calc.registerOperation("*", 400, (a, b) -> a * b);
- calc.registerOperation("/", 400, (a, b) -> a / b);
- calc.registerOperation("-", 100, (a) -> -a);
- }
- public int calculate(String s) {
- return calc.evaluate(s);
- }
- }
- ******************************************************************************/
- class Calculator {
- private Map<String, OperationInfo<UnaryOperation>> unaryOperations;
- private Map<String, OperationInfo<BinaryOperation>> binaryOperations;
- private Map<String, Function> functions;
- public Calculator() {
- this.unaryOperations =
- new HashMap<String, OperationInfo<UnaryOperation>>();
- this.binaryOperations =
- new HashMap<String, OperationInfo<BinaryOperation>>();
- this.functions = new HashMap<String, Function>();
- }
- // 注册一个一元运算符
- public void registerOperation(String operator, int precedence,
- UnaryOperation operation) {
- unaryOperations.put(
- operator, new OperationInfo<UnaryOperation>(precedence, operation));
- }
- // 注册一个二元运算符
- public void registerOperation(String operator, int precedence,
- BinaryOperation operation) {
- binaryOperations.put(
- operator, new OperationInfo<BinaryOperation>(precedence, operation));
- }
- // 注册一个函数
- public void registerFunction(String name, Function function) {
- functions.put(name, function);
- }
- // 调用Executor对表达式进行计算
- public int evaluate(String expression) {
- CalculatorExecutor executor =
- new CalculatorExecutor(unaryOperations, binaryOperations,
- functions, expression);
- return executor.run();
- }
- }
- // 对一元运算符的抽象
- interface UnaryOperation {
- public int apply(int operand);
- }
- // 对二元运算符的抽象
- interface BinaryOperation {
- public int apply(int operand1, int operand2);
- }
- // 对函数的抽象
- interface Function {
- public int apply(int ...operands);
- }
- // 用于打包operation和对应的precedence信息的小类
- class OperationInfo<OpType> {
- public final int precedence;
- public final OpType operation;
- public OperationInfo(int precedence, OpType operation) {
- this.precedence = precedence;
- this.operation = operation;
- }
- }
- // LL(1) Recursive Descent Syntax Directed Translator
- class CalculatorExecutor {
- private final Map<String, OperationInfo<UnaryOperation>> unaryOperations;
- private final Map<String, OperationInfo<BinaryOperation>> binaryOperations;
- private final Map<String, Function> functions;
- private final String stream;
- private int position;
- // 词法部分也合并到这个类里了
- private enum TokenType {
- INTEGER,
- NAME,
- OPERATOR,
- LPAREN,
- RPAREN,
- COMMA,
- EOS,
- ERROR
- }
- private class Token {
- public final TokenType type;
- public final Object payload;
- public final int columnNumber;
- public Token(TokenType type, int columnNumber) {
- this(type, columnNumber, null);
- }
- public Token(TokenType type, int columnNumber, Object payload) {
- this.type = type;
- this.payload = payload;
- this.columnNumber = columnNumber;
- }
- }
- private Stack<Token> tokens;
- public CalculatorExecutor(
- Map<String, OperationInfo<UnaryOperation>> unaryOperations,
- Map<String, OperationInfo<BinaryOperation>> binaryOperations,
- Map<String, Function> functions,
- String stream) {
- this.unaryOperations = unaryOperations;
- this.binaryOperations = binaryOperations;
- this.functions = functions;
- this.stream = stream;
- this.position = 0;
- this.tokens = new Stack<Token>();
- }
- public int run() {
- int value = evalExpr(Integer.MAX_VALUE);
- passNextToken(TokenType.EOS);
- return value;
- }
- private int evalExpr(int precedence) {
- int value = evalFactor(precedence);
- while (hasNextToken(TokenType.OPERATOR)) {
- Token token = nextToken();
- OperationInfo<BinaryOperation> info =
- binaryOperations.get((String)token.payload);
- if (info == null || info.precedence >= precedence) {
- pushBack(token);
- break;
- }
- value = info.operation.apply(value, evalExpr(info.precedence));
- }
- return value;
- }
- private int evalFactor(int precedence) {
- Token token = nextToken();
- if (token.type == TokenType.INTEGER) {
- return (Integer)token.payload;
- }
- if (token.type == TokenType.OPERATOR) {
- OperationInfo<UnaryOperation> info =
- unaryOperations.get((String)token.payload);
- if (info == null || info.precedence > precedence) {
- error(token);
- }
- return info.operation.apply(evalExpr(info.precedence));
- }
- if (token.type == TokenType.NAME) {
- Function func = functions.get((String)token.payload);
- if (func == null) {
- error(token);
- }
- ArrayList<Integer> args = new ArrayList<Integer>();
- passNextToken(TokenType.LPAREN);
- while (!hasNextToken(TokenType.RPAREN)) {
- args.add(evalExpr(Integer.MAX_VALUE));
- if (!hasNextToken(TokenType.COMMA)) {
- break;
- }
- nextToken();
- }
- passNextToken(TokenType.RPAREN);
- return func.apply(args.stream().mapToInt(x -> x).toArray());
- }
- if (token.type == TokenType.LPAREN) {
- int value = evalExpr(Integer.MAX_VALUE);
- Token rp = nextToken();
- if (rp.type != TokenType.RPAREN) {
- error(token);
- }
- return value;
- }
- error(token);
- return 0;
- }
- private boolean hasNextToken(TokenType ...expected) {
- Token token = nextToken();
- boolean status = Arrays.stream(expected).anyMatch(x -> x == token.type);
- pushBack(token);
- return status;
- }
- private void passNextToken(TokenType ...expected) {
- Token token = nextToken();
- if (!Arrays.stream(expected).anyMatch(x -> x == token.type)) {
- error(token);
- }
- }
- private void pushBack(Token token) {
- tokens.add(token);
- }
- private Token nextToken() {
- if (!tokens.isEmpty()) {
- return tokens.pop();
- }
- while (position < stream.length() &&
- Character.isWhitespace(stream.charAt(position))) {
- ++position;
- }
- if (position >= stream.length()) {
- return new Token(TokenType.EOS, position);
- }
- final int start = position;
- final char ch = stream.charAt(position++);
- switch (ch) {
- case '(': return new Token(TokenType.LPAREN, start);
- case ')': return new Token(TokenType.RPAREN, start);
- case ',': return new Token(TokenType.COMMA, start);
- default: --position; break;
- }
- if (Character.isDigit(ch)) {
- return nextNumber();
- }
- if (Character.isAlphabetic(ch)) {
- return nextName();
- }
- return nextOperator();
- }
- private Token nextNumber() {
- final int start = position;
- while (position < stream.length() &&
- Character.isDigit(stream.charAt(position))) {
- ++position;
- }
- return new Token(TokenType.INTEGER, start,
- Integer.parseInt(stream.substring(start, position)));
- }
- private Token nextName() {
- final int start = position;
- while (position < stream.length() &&
- Character.isAlphabetic(stream.charAt(position))) {
- ++position;
- }
- return new Token(TokenType.NAME, start,
- stream.substring(start, position));
- }
- private Token nextOperator() {
- final int start = position;
- while (position < stream.length()) {
- final char ch = stream.charAt(position);
- if (Character.isWhitespace(ch) ||
- Character.isDigit(ch) ||
- Character.isAlphabetic(ch) ||
- ch == '(' || ch == ')' || ch == ',') {
- break;
- }
- ++position;
- }
- return new Token(TokenType.OPERATOR, start,
- stream.substring(start, position));
- }
- private void error(Token token) {
- throw new RuntimeException(
- "Syntax error: unexpected token at column " +
- (token.columnNumber+1) + " -- " + token.type.name() +
- (token.payload == null ? "" : " (" + token.payload.toString() + ")"));
- }
- }
复制代码 |
|