内容:掌握语法分析的基本思想,并用高级语言编写逆波兰式生成程序;
要求:利用逆波兰式生成算法编写程序,将从键盘上输入的算术表达式(中缀表达式)转化成逆波兰式。
逆波兰表达式的生成过程涉及到运算符的优先级,下表中列出几个常用运算符的优先关系。
常用运算符优先关系矩阵
+ | - | * | / | ↑ | ( | ) | |
+ | > | > | < | < | < | < | > |
- | > | > | < | < | < | < | > |
* | > | > | > | > | < | < | > |
/ | > | > | > | > | < | < | > |
↑ | > | > | > | > | > | < | > |
( | < | < | < | < | < | < | = |
) | > | > | > | > | > |
| > |
如上表所示的优先关系矩阵表示了+,-,*,/,↑,(,)等七种运算符之间的相互优先关系。“>、<、=”三种符号分别代表“大于”、“小于”、“相等”三种优先关系。左边的“=”与右边的“(”之间没有优先关系存在,所以表中为空白。
逆波兰表达式生成算法的关键在于比较当前运算符与栈顶运算符的优先关系,若当前运算符的优先级高于栈顶运算符,则当前运算符入栈,若当前运算符的优先级低于栈顶运算符,则栈顶运算符退栈。
下面给出了逆波兰表达式生成算法的流程图。(为了便于比较相邻运算符的优先级,需要设立一个工作栈,用来存放暂时不能处理的运算符,所以又称运算符栈)。
代码
package report;
import java.util.ArrayList;
public class No2 {
// 存放运算符优先关系矩阵
private String[][] chars;
// 存放运算符栈(index=0表示栈底,index=size()-1表示栈顶)
private ArrayList<String> stack;
// 存放输入串
private ArrayList<String> inStr;
// 存放输出串
private ArrayList<String> outStr;
public static void main(String[] args) {
No2 no2 = new No2();
String str = "(a+b)*c/d";
no2.init(str);
no2.mainFunc();
for (String currentChar : no2.outStr) {
System.out.print(currentChar);
}
}
private void mainFunc() {
// 从左往右扫描中缀表达式
label1: for (String currentChar : this.inStr) {
// 输入串为空?
if (currentChar.equals("#")) {
// 栈为空?
while (true) {
if (this.stack.get(this.stack.size() - 1).equals("#")) {
break label1;
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
} else {
// 运算符?
if (!this.isChar(currentChar)) {
// 输出
this.outStr.add(currentChar);
continue;
} else {
while (true) {
// 栈是否为空?
if (this.stack.get(this.stack.size() - 1).equals("#")) {
// 入栈
this.stack.add(currentChar);
continue label1;
} else {
// 比较当前运算符与栈顶运算符的优先级
if (isFirst(currentChar)) {
// 入栈
this.stack.add(currentChar);
continue label1;
} else {
// 当前运算符是')'
if (currentChar.equals(")")) {
while (true) {
// 栈顶为'('
if (this.stack.get(this.stack.size() - 1).equals("(")) {
// 退栈
this.stack.remove(this.stack.size() - 1);
continue label1;
} else {
// 栈为空?
if (this.stack.get(this.stack.size() - 1).equals("#")) {
System.out.println("ERROR");
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
}
} else {
// 退栈输出
this.outStr.add(this.stack.get(this.stack.size() - 1));
this.stack.remove(this.stack.size() - 1);
continue;
}
}
}
}
}
}
}
}
private void init(String str) {
System.out.println(str);
this.stack = new ArrayList<>();
this.inStr = new ArrayList<>();
this.outStr = new ArrayList<>();
// 输入运算符优先关系矩阵8*7
this.chars = new String[][] { { ">", ">", "<", "<", "<", "<", ">" }, { ">", ">", "<", "<", "<", "<", ">" },
{ ">", ">", ">", ">", "<", "<", ">" }, { ">", ">", ">", ">", "<", "<", ">" },
{ ">", ">", ">", ">", ">", "<", ">" }, { "<", "<", "<", "<", "<", "<", "=" },
{ ">", ">", ">", ">", ">", "", ">" }, { "<", "<", "<", "<", "<", "<", "<" } };
// 输入输入串
String[] temps = str.split("");
for (String temp : temps) {
this.inStr.add(temp);
}
this.inStr.add("#");
// 输入运算符栈
this.stack.add("#");
}
// 运算符?
private boolean isChar(String currentChar) {
return "+-*/↑()".contains(currentChar);
}
// 比较当前运算符与栈顶运算符的优先级
private boolean isFirst(String currentChar) {
String stackChar = this.stack.get(this.stack.size() - 1);
int x = "+-*/↑()#".indexOf(stackChar);
int y = "+-*/↑()#".indexOf(currentChar);
return this.chars[x][y].equals("<");
}
}
运行结果