版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28929579/article/details/90679677
RPN逆波兰式
什么是RPN逆波兰式?
逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后),举例:
Input: 2 1 + 3 *
Output: 9
Explanation: ((2 + 1) * 3) = 9
问题:设计一个栈来实现RPN功能,包含如下几点:
- 接受以空格区分的字符串,字符串包含数字和操作符。
- 操作符包含 + - * / sqrt undo clear
- 遇到操作符计算后把结果压入栈。
- 处理后输出显示结果。
- 栈存储15位精度的小数,但只显示10位小数。
- 当操作元素不够时,报错 比如 operator<*> (position:<10>):insufficient parameters
- 报错后终止后续已输入的内容并显示已处理的数据。
- sqrt是开平方,undo是撤销上一步内容,clear是清空栈元素。
举例1
Input: 5 2
Output: stack: 5 2
举例2:
Input: 2 sqrt
Output: stack: stack:1.4142135623
Input: clear 9 sqrt
Output: stack:3
Input: clear
Output: stack:
举例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
举例4:
Input: 1 2 3 4 5
Output: stack: stack:1 2 3 4 5
Input: * * * *
Output: stack: stack:120
举例5:
Input: 1 2 3 * 5 + * * 6 5
Output: stack: operator * (position:15):insufficient parameters stack:11
思考
题目要求都用栈了,这里就用LinkedList来实现栈,还需一个数组来记录以及输入的值,关键是undo操作,是从输入开始就重新计算还是只回撤上一步了?我考虑到设计sqrt、/等操作,回撤操作会丢失精度,那还是从头开始计算一遍吧。
实现
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);
}
}
}
这是一道面试题,但是为什么没过就很尴尬,先记录下吧,或许等过些日子就能发现问题了。。。也欢迎各位指出不足