Implement RPN (Reverse Polish Notation)

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/qq_28929579/article/details/90679677

What is RPN Reverse Polish Notation?

Reverse Polish Notation (Reverse Polish notation, RPN, or reverse Polish notation), also called postfix expression (written after the operator operand), for example:

Input: 2 1 + 3 *
Output: 9
Explanation: ((2 + 1) * 3) = 9

Problem: Design a RPN stack to implement features, including the following:

  1. Accepting space-separated string of numbers and comprising operators.
  2. Operator comprising + - * / sqrt undo clear
  3. After the operator encounters the calculation result onto the stack.
  4. Processed output shows the result.
  5. Stack memory 15 decimal precision, but only displays 10 decimal places.
  6. When the operating element is insufficient, such being given operator <*> (position: <10>): insufficient parameters
  7. Subsequent to the termination after the error has been inputted and displaying the processed data.
  8. sqrt is the square root, undo the last step is the removal of content, clear elements of the stack is empty.
    For example 1
    Input: 5 2
    Output: stack: 5 2
    Example 2
    Input: 2 sqrt
    Output: stack: stack:1.4142135623
    Input: clear 9 sqrt
    Output: stack:3
    Input: clear
    Output: stack:
    For example 3
    Input: 5 4 3 2
    Output: stack: stack:5 4 3 2
    Input: undo undo *
    Output: stack: stack:20
    Input: 5 *
    Output: stack: stack:100
    For example 4
    Input: 1 2 3 4 5
    Output: stack: stack:1 2 3 4 5
    Input: * * * *
    Output: stack: stack:120
    For example 5
    Input: 1 2 3 * 5 + * * 6 5
    Output: stack: operator * (position:15):insufficient parameters stack:11

Think

All the questions asked by the stack, to achieve here with LinkedList stack, as well as the need to record an array of input values, the key is to undo the operation, is input from the beginning to recalculate or just retracement of the last step? I take into account the design sqrt, / etc, operating retracement lose precision, it is still computing it again from scratch.

achieve

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;

public class RPN {
    private LinkedList<BigDecimal> resultList = new LinkedList<>();
    private ArrayList<String> recordList = new ArrayList<>();

    //单个入栈
    private void push(BigDecimal val) {
        resultList.addFirst(val);
    }

    //查看栈顶元素但不移除
    private BigDecimal peek() {
        return resultList.getFirst();
    }

    //出栈
    private BigDecimal pop() {
        return resultList.removeFirst();
    }

    //判空
    private boolean empty() {
        return resultList.isEmpty();
    }

    //打印栈元素(显示10位精度)
    @Override
    public String toString() {
        StringBuilder str = new StringBuilder("stack:");
        System.out.print(str);
        for (int i = resultList.size() - 1; i >= 0; i--) {
            BigDecimal result = resultList.get(i);
            BigDecimal intValue = new BigDecimal(result.intValue());
            if (intValue.compareTo(result) != 0) {
                String showStr = result.setScale(10, BigDecimal.ROUND_DOWN).stripTrailingZeros().toPlainString();
                str.append(showStr + " ");
                System.out.print(showStr + " ");
            } else {
                str.append(intValue + " ");
                System.out.print(intValue + " ");
            }
        }
        System.out.println();
        return str.toString();
    }

    private boolean inputVal(String str) {
        String[] vals = str.split("\\s+");
        for (String val : vals) {
            recordList.add(val);
            if (isOperator(val)) {
                boolean flag = operator(val);
                if (!flag) {
                    toString();
                    return false;
                }
            } else {
                try {
                    BigDecimal num = new BigDecimal(val);
                    resultList.addFirst(num);
                } catch (NumberFormatException e) {
                    System.out.println("Please enter the correct number!");
                    recordList.remove(recordList.size() - 1);
                    break;
                }
            }
        }
        return true;
    }

    public void pushs(String str) {
        if (inputVal(str)) {
            toString();
        }
    }

    private void reset() {
        this.resultList = new LinkedList<>();
        this.recordList = new ArrayList<>();
    }

    private boolean operator(String opr) throws NoSuchElementException {
        int position = recordList.size();
        if (opr.equals("undo")) {
            // 重新计算
            if (position >= 3) {
                StringBuilder preStr = new StringBuilder();
                for (int i = 0; i <= position - 3; i++) {
                    preStr.append(recordList.get(i) + " ");
                }
                reset();
                inputVal(preStr.toString());
            }
        } else if (opr.equals("clear")) {
            reset();
        } else {
            BigDecimal topNum = null;
            try {
                topNum = pop();
                if (opr.equals("+")) {
                    BigDecimal laterNum = pop();
                    push(topNum.add(laterNum));
                } else if (opr.equals("-")) {
                    BigDecimal laterNum = pop();
                    push(laterNum.subtract(topNum));
                } else if (opr.equals("*")) {
                    BigDecimal laterNum = pop();
                    push(laterNum.multiply(topNum));
                } else if (opr.equals("/")) {
                    BigDecimal laterNum = pop();
                    push(laterNum.divide(topNum, 15, BigDecimal.ROUND_HALF_UP));
                } else if (opr.equals("sqrt")) {
                    push(sqrt(topNum).setScale(15, BigDecimal.ROUND_HALF_UP));
                }
            } catch (NoSuchElementException e) {
                System.out.print("operator " + opr + " (position:" + (position * 2 - 1) + "):insufficient parameters ");
                //把成功的计算结果塞回去
                push(topNum);
                // 截取记录符合的输入
                recordList.remove(--position);
                return false;
            }
        }
        return true;
    }

    private boolean isOperator(String opr) {
        return "+".equals(opr) || "-".equals(opr) || "*".equals(opr) || "sqrt".equals(opr) || "/".equals(opr) || "undo".equals(opr) || "clear".equals(opr);
    }

    private static BigDecimal sqrt(BigDecimal num) {
        if (num.compareTo(BigDecimal.ZERO) < 0) {
            return BigDecimal.ZERO;
        }
        BigDecimal x = num.divide(new BigDecimal("2"), MathContext.DECIMAL128);
        while (x.subtract(x = sqrtIteration(x, num)).abs().compareTo(new BigDecimal("0.0000000000000000000001")) > 0) ;
        return x;
    }

    private static BigDecimal sqrtIteration(BigDecimal x, BigDecimal n) {
        return x.add(n.divide(x, MathContext.DECIMAL128)).divide(new BigDecimal("2"), MathContext.DECIMAL128);
    }

    public static void main(String[] args) {
        RPN rpn = new RPN();
        Scanner sc = new Scanner(System.in);
        // 1 2 3 * * 2 /
        // 1 2 3 * 5 + * * 6 5
        while (true) {
            String input = sc.nextLine();
            rpn.pushs(input);
        }
    }
}

这是一道面试题,但是为什么没过就很尴尬,先记录下吧,或许等过些日子就能发现问题了。。。也欢迎各位指出不足

Guess you like

Origin blog.csdn.net/qq_28929579/article/details/90679677