将算术表达式转换成另一种形式:后缀表达式。
先来介绍后缀表达式。
后缀表达法
日常算术表达式是将操作符( operator)(+,一,术,/)放在两个操作数(operands)(数字,或代表数字的字母)之间的。因为操作符写在操作数的中间,所以把这种写法称为中缀表达法。于是,日常我们写的算术表达式就形如2+2,4/7,或者用字母代替数字,如A+B和A/B等。
在后缀表达式中(也称作波兰逆序表达式( Reverse Polish Notation),或者RPN,它是由一位波兰的数学家发明的),操作符跟在两个操作数的后面。这样,A+B就成为AB+,A/B成为AB/。更复杂的中缀表达式同样日以转换成后缀表达式,如下所示。稍后会解释后缀表达式是如何产生的。
中缀表达式 后缀表达式
A+B-C AB+C-
A*B/C AB*C/
A+B*C ABC*+
人类如何将中缀表达式转换成后缀表达式
将中缀表达式转换成后缀表达式的规则和计算中缀表达式值的规则类似。但是,还是有点变化
的。将中缀表达式转换成后缀表达式不用做算术运算。它不求中缀表达式的值,只是把操作数和操作符重新排列成另一种形式:后缀表示法。然后再求后缀表达式的结果。和以前一样,从左到右地读取中缀表达式,顺序地查看每一个字符。在此过程中,将这些操作数和操作符复制到后缀表达式输出的字符串中。关键是要知道每个字符该何时输出。
如果中缀字符串中的字符是操作数,则立即把它复制到后缀字符串中。这就是说,如果看到中
缀字符串中的A时,就立即把A写到后缀字符串里。一定不要延迟:读到操作数就复制它们,而
木去管多久后才能复制和它们关联的操作符。
决定何时复制操作符更复杂一些,但它的规则和计算中缀表达式时一样。一旦可以利用操作符
求中缀表达式的某部分的值,就把该运算符复制到后缀字符串中。
在栈中保存操作符,因为在中缀式和后缀式的操作数顺序是一样的,所以可以读到操作数的时候,直接就把操作数输入到结果中。
完整代码
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;
/**
* @author
* @date 2018/3/28 18:05
*/
public class InToPost {
private Stack<Character> stack;
private String input;
private String output = "";
public InToPost(String input) {
this.input = input;
int stackSize = input.length();
stack = new Stack();
}
public String doTrans() {
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
switch (ch) {
case '+':
case '-':
gotOper(ch, 1); // 如果是+ 和 - 出栈操作,运算符优先级为1
break;
case '*':
case '/':
gotOper(ch, 1); // 如果是 / 和 * 出栈操作,运算符优先级为2
break;
case '(':
stack.push(ch); // 如果是( 直接push入栈
break;
case ')':
gotParen(ch); //如果是 ) 出栈操作
break;
default:
output += ch; // 不是运算符 ,写入结果
break;
}
}
while (!stack.isEmpty()) {
output= output+ stack.pop(); //遍历完表达式,运算符栈中还有元素,直接pop
}
return output;
}
/**
* 当前操作符是)时,之前操作符是( 时,(直接出栈,不是就把(之前的操作符全部写入结果
* @param ch 后括号
*/
private void gotParen(char ch) {
while (!stack.isEmpty()) {
char chx = stack.pop();
if (chx == '(') {
break;
} else output = output+chx;
}
}
/**
*
* @param opThis 运算符
* @param prec 运算符的优先级
*/
private void gotOper(char opThis, int prec) {
while (!stack.isEmpty()) {
char opTop = stack.pop(); // 之前运算符
if (opTop == '(') { // 如果是( 运算符入栈
stack.push(opTop);
break;
} else { //如果是操作符
int prec1;
if (opTop == '+' || opTop == '-') { //看之前一个操作符的优先级
prec1 = 1;
} else {
prec1 = 2;
}
if (prec1 < prec) { //如果当前操作符优先级比之前的优先级高
stack.push(opTop); // 之前的操作符入栈
break;
} else {
output = output+opTop; //否则之前的操作符写入结果
}
}
}
stack.push(opThis); //当前操作符入栈
}
public static void main(String[] args) throws Exception{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
InToPost transfor = new InToPost(s);
String output = transfor.doTrans();
System.out.println(output);
}
}
// A*(B+C)-D/(E+F)
测试结果