最近学习了栈,为了巩固知识,照着书实现了一个有关于栈的应用的例子:将中缀表达式转化为后缀表达式。
这里先来明白什么是中缀表达式:我们正常使用的算式,如a + b * c 就是一个中缀表达式。中缀表达式的特点就是运算符在中间。
后缀表达式就是 运算符在后面,像上面的式子如果转化为后缀表达式就为 a b * + 。
这里以测试用例:A*B(B+C)-D/(E+F) 来为大家介绍一下转化的过程。
由中缀表达式中读取的字符 | 分解中缀表达式的过程 | 求后缀表达式的过程 | 栈中的内容 | 规则 |
A |
| A |
| 将操作数A写至后缀(后缀表达式) |
* | A* | A | * | 若栈为空,将*进栈 |
( | A*( | A | *( | 将操作数(入栈 |
B | A*(B | AB | *( | 将操作数B写入后缀 |
+ | A*(B+ | AB | * | 栈非空,故弹出一项 |
| A*(B+ | AB | *( | 有(,故将(进栈 |
| A*(B+ | AB | *(+ | 将操作数+进栈 |
C | A*(B+C | ABC | *(+ | 将操作数C写入后缀中 |
) | A*(B+C) | ABC+ | *( | 遇见),弹出栈中的位于(之后的内容即+,写至后缀 |
| A*(B+C) | ABC+ | * | 若有(,直接将其出栈 |
- | A*(B+C) | ABC+* | - | 将*出栈,写入后缀,再将-进栈 |
D | A*(B+C)-D | ABC+*D | - | 将D写入后缀 |
/ | &-D/ | &D | -/ | 将\进栈 |
( | &-D/( | &D | -/( | 将(入栈 |
E | &-D/(E | &DE | -/( | 将E写入后缀 |
+ | &-D/(E+ | &DE | -/ | 栈弹出一项 |
| &-D/(E+ | &DE | -/( | 出栈的为(,因此将其重新进栈 |
| &-D/(E+ | &DE | -/(+ | 将+进栈 |
F | &-D/(E+F | &DEF | -/(+ | 将F写入后缀 |
) | &-D/(E+F) | &DEF | -/( | 遇见),弹出栈中的位于(之后的内容即+,写至后缀 |
| &-D/(E+F) | &DEF+ | -/ | 遇见(,将其出栈 |
| &-D/(E+F) | &DEF+/- |
| 将剩下栈中的元素全部出栈,写入后缀 |
A*(B+C)-D/(E+F)
如果大家肯定还不太明白,大家可以自己百度一下,这里就不多做介绍了。
实现的算法就是上面的转化过程,下面是源码,包含解释:
1.栈类stackX
package infix; /* * 这是一个自己定义的,存储数据的栈 */ public class StackX { private int maxSize; private char[] stackArray; private int top; public StackX(int s){ maxSize = s; stackArray = new char[maxSize]; top = -1; } //入栈操作 public void push(char value){ stackArray[++top] = value; } //出栈操作 public char pop(){ return stackArray[top--]; } //查看栈顶元素 public char peek(){ return stackArray[top]; } //判断是是否为空 public boolean isEmpty(){ return (top == -1); } public int size(){ return top+1; } //查看在位置n的元素 public char peekN(int n){ return stackArray[n]; } //打印从栈底到栈顶的元素 public void displayStack(String s){ System.out.print(s); System.out.print("Stack (bottom-->top):"); for (int j = 0; j < size(); j++) { System.out.print(peekN(j)); System.out.print(' '); } System.out.println(""); } }
2.InToPost类,存放的操作方法
package infix; public class InToPost { private StackX stack; private String input; private String output=""; public InToPost(String in){ input = in; //输入的要分析的字符串 int stackSize = input.length(); stack = new StackX(stackSize); } /* * 将中缀表达式转化为后缀表达式 * 如果读取的单个字符不是基础运算符,则将这个字符放入output中。output中的数据只会增加,不会变化 */ public String doTrans(){ for (int i = 0; i < input.length(); i++) { char ch = input.charAt(i); //从input中取出第i个字符 stack.displayStack("For " + ch + " "); //调用StackX中的方法来显示ch switch (ch) { case '+': case '-': gotOper(ch, 1); break; case '*': case '/': gotOper(ch, 2); break; case '(': stack.push(ch); break; case ')': gotParen(ch); break; default: output = output + ch; break; } } //将剩余的栈中元素全部出栈。出栈的顺序就代表了运算的顺序。 while(!stack.isEmpty()){ stack.displayStack("While "); output = output + stack.pop(); } stack.displayStack("End "); return output; } public void gotOper(char opThis, int prec1){ while (!stack.isEmpty()) { //循环将栈中的char类型出栈 char opTop = stack.pop(); if (opTop == '(') { stack.push(opTop); //将出栈的‘(’元素进栈 break; }else { int prec2; //判断onTop的优先级 if (opTop=='+'||opTop == '-') { //设置加减的优先级为1 prec2 = 1; }else { //其他的优先级为2 prec2 = 2; } if (prec2 < prec1) { //当传入的onThis的优先级prec1大于出栈的opTop的优先级 stack.push(opTop); //将出栈的opTop进栈 break; }else { output = output + opTop; //如果出栈的opTop的算术优先级比opThis的大,则将其放到output中 } } } stack.push(opThis); } public void gotParen(char ch){ while (!stack.isEmpty()) { char chx = stack.pop(); //读取到‘(’,就出栈在‘(’和‘)’之间的所有元素 if (chx == '(') { break; }else { output = output + chx; //如果读到了‘)’,则将stack栈中的符号放入output中 } } } }
3.主类:
package infix; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /* * 用栈来实现把一个中缀表达式,转化为一个后缀表达式 */ public class InfixApp { public static void main(String[] args) throws IOException { String input,output; while(true){ System.out.println("输入要运算式: "); System.out.flush(); input = getString(); if (input.equals("")) { System.out.println("输入不要为空"); break; } //创建InToPost对象 InToPost theTrans = new InToPost(input); //调用doTrans方法 output = theTrans.doTrans(); System.out.println("转化后的运算式为: " + output + '\n'); } } //用于读取输入流中的数据 public static String getString() throws IOException{ InputStreamReader in = new InputStreamReader(System.in); BufferedReader buffer = new BufferedReader(in); String s = buffer.readLine(); return s; } }
运行结果:
输入要运算式: A*(B+C)-D/(E+F) For A Stack (bottom-->top): For * Stack (bottom-->top): For ( Stack (bottom-->top):* For B Stack (bottom-->top):* ( For + Stack (bottom-->top):* ( For C Stack (bottom-->top):* ( + For ) Stack (bottom-->top):* ( + For - Stack (bottom-->top):* For D Stack (bottom-->top):- For / Stack (bottom-->top):- For ( Stack (bottom-->top):- / For E Stack (bottom-->top):- / ( For + Stack (bottom-->top):- / ( For F Stack (bottom-->top):- / ( + For ) Stack (bottom-->top):- / ( + While Stack (bottom-->top):- / While Stack (bottom-->top):- End Stack (bottom-->top): 转化后的运算式为: ABC+*DEF+/- 输入要运算式: