波兰式
(1) 相关概念:
百度
维基
(2) 分析
运算式的组成:操作数和操作符
操作数:整数和浮点数
操作符:+、-、*、/、( 、)
因为需要从右至左依次扫描运算式,每次扫描到的都是单个字符串,所以当遇到字符为数字和小数点时需要将其存放到一个临时的变量中,便于浮点数的复原,和数字为负数的情况。而javaAPI中Character提供了判断单个字符是否为数字的方法,以及StringBuffer用于追加字符的方法。
(3) 流程
- 从右至左扫描运算式
- 如果当前字符是数字或者小数点时,追加到StringBuffer对象中,跳出当前循环
- 如果当前遍历到最左边时,当前字符不是左括号时,追加到StringBuffer对象中,跳出循环
- 如果当前字符不是左括号和前一个字符不是右括号并且不为数字时,追加到StringBuffer对象中,跳出当前循环
- 如果StringBuffer对象的字符串长度不等于0的时候将其保存的字符串反转之后压入到stack2栈中,
- 如果当前stack1栈中是空栈或者栈顶元素是右括号,直接压入到栈中,跳出当前循环
- 如果当前字符不是左括号的情况:
7.1 对当前字符和stack1栈顶元素进行优先级的判断,如果当前字符优先级大于等于栈顶元素时,压入到stack1中,并跳出循环
7.2 否则栈顶元素出栈,并压入到stack2栈中,回到步骤6 - 如果运算式扫描完毕后,执行跟步骤5一样的操作
- 如果stack1栈中还存在元素,则将其依次出栈,并压入到stack2中
(4) 实现代码
首先需要两个栈
/**
* stack1:存放操作符
* stack2:存放波兰式
*/
private Stack stack1 = new Stack();
private Stack stack2 = new Stack();
处理运算式:
/**
* 该方法将从右到左扫描运算式
* 将其转化成波兰式,并将结果返回
* temp:用于存放从运算式取出的当个字符
* operand:存放操作数
* @param str 运算式
* @return 转化后的波兰式
*/
public String getPolish(String str) {
char temp;
StringBuffer operand = new StringBuffer();
for (int i = str.length() - 1; i >= 0; i--) {
temp = str.charAt(i);
// (1)、如果字符是数字类型或者为(.)即就是浮点型,则追加到operand中
if (Character.isDigit(temp) || temp == '.') {
operand.append(temp);
continue;
}
// (2.1)、如果i等于0和temp不等于小左括号'('
if (i == 0 && temp != '(') {
operand.append(temp);
break;
}
// (2.3)、向前看多一位字符,如果该字符不为数字,则说明该操作符为单目运算符,则追加到operand的末尾
if(temp != '(' && !Character.isDigit(str.charAt(i - 1)) && str.charAt(i - 1) != ')') {
operand.append(temp);
removeAll(operand);
continue;
}
// (2.3)、如果operand不为空,则将其进行反转之后(倒序)再压入到栈中
removeAll(operand);
while (true) {
// (3)、如果当前stack1为空栈或者当前栈顶元素为右小括号 ')',则压入到stack1中
if (stack1.empty() || ")".equals(stack1.peek())) {
stack1.push(Character.toString(temp));
break;
}
// (4)、如果temp不是左小括号'(',则进行优先级判断
if (temp != '(') {
// (4.1)、如果temp的优先级比stack1栈顶元素的优先级高或者一样时,则压入到stack1中
if (getPriority(Character.toString(temp)) <= getPriority(stack1.peek())) {
stack1.push(Character.toString(temp));
break;
}
// (4.2)、temp比stack1栈顶元素小,则stack1栈顶元素出栈,压入到stack2中。
stack2.push(stack1.pop());
// 接着跳出当前循环,返回到步骤(3)
continue;
}
// (5)、temp为左括号'(',则将stack1中元素一一弹出,则直到遇到右小括号为止
while (!stack1.empty() && !")".equals(stack1.peek())) {
stack2.push(stack1.pop());
}
// (6)、栈顶元素为右小括号')'时,将其舍弃
stack1.pop();
// (7)、结束while循环,舍弃左小括号'('
break;
}
}
// (8)、如果operand里面还有内容将其反转之后(倒序)压入stack2中
removeAll(operand);
// (9)、如果stack1不为空栈,则将其栈顶元素弹出,直到为空栈为止
while (!stack1.empty()) {
stack2.push(stack1.pop());
}
// (10)、将stack2栈中全部元素压入到stack1中方便进行计算
while(!stack2.empty()){
stack1.push(stack2.pop());
}
return stack1.toString();
}
优先级
/**
* 该方法返回操作符对应的优先级,优先级越高返回的数字越小
* @param str 操作符
* @return 返回优先级数字
*/
private int getPriority(String str) {
switch (str) {
case "+":
case "-":
return 3;
case "*":
case "/":
return 2;
case "(":
case ")":
return 1;
default :
return 0;
}
}
(5) 测试代码
Polish p1 = new Polish();
Polish p2 = new Polish();
Polish p3 = new Polish();
Polish p4 = new Polish();
System.out.println(p1.getPolish("(3+4)*5-6"));
System.out.println(p2.getPolish("(-3+4)*5-6"));
System.out.println(p3.getPolish("(3.1+4.5)*5-6.2"));
System.out.println(p4.getPolish("-3.1+4.5*5-6.2"));
(6) 测试结果
(7) 计算实现
由于在(5)中已经提前预处理了,所以只需要增加一个栈用来保存操作数用于计算就行。
(7.1) 流程
依次将stack1中元素弹出,如果遇到是操作数,则压入到新增加的栈中;否则,将新增的栈中栈顶元素弹出两个进行对应的计算并将计算结果压回到栈中。
(7.2) 代码
/**
* 该方法用于将波兰式进行数学计算
*/
private String mathematical(){
Stack operand = new Stack();
while (!stack1.empty()) {
switch (stack1.peek()) {
case "+":
stack1.pop();
stack1.push(operand.pop().add(operand.pop()).toString());
break;
case "-":
stack1.pop();
stack1.push(operand.pop().subtract(operand.pop()).toString());
break;
case "*":
stack1.pop();
stack1.push(operand.pop().multiply(operand.pop()).toString());
break;
case "/":
stack1.pop();
stack1.push(operand.pop().divide(operand.pop()).toString());
break;
default:
operand.push(new BigDecimal(stack1.pop()));
}
}
return operand.toString();
}
(7.3) 测试
Polish p1 = new Polish();
Polish p2 = new Polish();
Polish p3 = new Polish();
Polish p4 = new Polish();
System.out.println(p1.getPolish("(3+4)*5-6"));
System.out.println(p2.getPolish("(-3+4)*5-6"));
System.out.println(p3.getPolish("(3.1+4.5)*5-6.2"));
System.out.println(p4.getPolish("-3.1+4.5*5-6.2"));
System.out.println(p1.mathematical());
System.out.println(p2.mathematical());
System.out.println(p3.mathematical());
System.out.println(p4.mathematical());