提出问题
上周数据结构实验课要求写一个中缀式转后缀式,并计算后缀式的值。成熟思路网上有很多,这里不再造轮子讲一遍了。
例如这篇:https://blog.csdn.net/Ring_k/article/details/79598961,这篇文章的举例部分,把中缀式转后缀式的过程一步步写了出来,显示了操作数读取、操作符栈、输出的状态,作者很细心,博主就是参考的这篇文章介绍的原理,感谢作者的原理讲解。
但是原文仅支持单个位数的操作数读取与运算,即操作数取值应为于‘0’-‘9’之间。如果操作数是67、88、45678这种多位操作数呢?
解决问题
原文中的中缀式转后缀式,该过程的本质是按字符读取每个操作数/操作符,一个字符塞入数组的一个单元格中,数组的一个单元格,当然只能容纳一个元素,即一个char占一个数组单元格。如每次读取一整个多位数呢?
博主想到了使用队列。使用Java泛型,把每个数组的单元格数据类型设置为一个队列。这样一个单元格就能存入多位操作数了,原则上,一个操作数/一个操作符/一个'('或')' 占用一个队列。
中缀表达式转后缀表达式具体运算时,原过程是依次读取数组中的每个单元格。现在,数组中每个单元格由一个char变为了一个队列,那么我们可以把队列中的多位操作数依次出队,这样,实现多位操作数的运算。
Java代码
本文代码参考了慕课网liuyubobobo老师的《Java语言玩转数据结构》中的“动态数组”,“动态数组实现栈”,“动态数组实现队列”,以这三个自定义的数据类型为基础,实现中缀表达式转后缀表达式算法原理。这三个自定义的数据类型的使用只是更加方便,原理还是一样的,java.util.Stack和java.util.Queue也可以做到。看不懂源码的可以参考本文前半部分的原理,自己动手实现学习效果更好哦。
附上博主关于bobo老师《Java语言玩转数据结构》的github学习代码仓库,持续更新中:https://github.com/JellyfishMIX/play_with_data_structures_java
工程目录结构:
InfixExpsToPostfixExps为中缀表达式转后缀表达式的实现过程
动态数组:
package com.algorithm.array;
public class Array<E> { //泛型
private E[] data;
private int size;
// 构造函数,传入数组的容量capacity构造Array
public Array(int capacity) {
data = (E[]) new Object[capacity]; // java不支持new一个泛型类型的静态数组,需要中转一下。new一个Object类型的动态数组,然后强制转换成泛型类型
size = 0;
}
// 无参的构造函数,默认数组的容量capacity=10
public Array() {
this(10);
}
// 获取数组中元素的个数
public int getSize() {
return size;
}
// 获取数组的容量
public int getCapacity() {
return data.length;
}
// 判断数组是否为空
public boolean isEmpty() {
return size == 0;
}
// 向指定位置添加新元素
public void add(int index, E e) {
if (index < 0) {
throw new IllegalArgumentException("getArrayElem failed. Require index>=0");
}
if (index > size) {
throw new IllegalArgumentException("getArrayElem failed. Require index<=size");
}
// 若数组差1将满,则新建扩容数组,把原数组中数据逐个挪入新数组中,实现动态数组
if (size == data.length-1) {
resize(2 * data.length);
}
for (int i = size - 1; i >= index; i--) {
data[i + 1] = data[i];
}
data[index] = e;
size++;
}
// 向数组开头添加一个新元素
public void addFirst(E e) {
this.add(0, e);
}
// 向数组末尾添加一个新元素
public void addLast(E e) {
this.add(size, e);
}
// 删除指定位置的元素,返回删除的元素
public E deleteByIndex(int index) {
if (index < 0) {
throw new IllegalArgumentException("getArrayElem failed. Require index>=0");
}
if (index > size) {
throw new IllegalArgumentException("getArrayElem failed. Require index<=size");
}
E ret = data[index];
for (int i = index; i < size; i++) {
data[i] = data[i+1];
}
size--;
data[size] = null; // data[]中存放着一个个类对象的引用,data[size]还占用着一个引用,可以设为空,Java垃圾回收技术会释放掉占用的内存。非必须。该情况被称为loitering objects,注意: loitering objects != memory leak
if (size == data.length/4 && data.length/2 != 0) {
this.resize(data.length/2);
}
return ret;
}
// 删除数组开头元素
public E deleteFirst() {
E ret = deleteByIndex(0); //E ret 是作为接收deleteByIndex()的返回值
return ret;
}
// 删除数组末尾元素
public E deleteLast() {
E ret = deleteByIndex(size-1); //E ret 是作为接收deleteByIndex()的返回值
return ret;
}
// 删除指定的某个元素
public void delete(E e) {
int index = find(e);
if (index != -1) {
E ret = deleteByIndex(index); //E ret 是作为接收deleteByIndex()的返回值,无实际作用
}
}
// 获得index索引位置元素
public E get(int index) {
if (index < 0) {
throw new IllegalArgumentException("getArrayElem failed. Require index>=0");
}
if (index >= size) {
throw new IllegalArgumentException("getArrayElem failed. Require index<size");
}
return data[index];
}
// 获得第一个元素
public E getFirst() {
return get(0);
}
// 获得最后一个元素
public E getLast() {
return get(size-1);
}
// 设置index索引位置元素
public void set(int index, E e) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("setArrayElem failed. Require index>=0 && index<=size");
}
data[index] = e;
}
// 查找数组中是否有元素e
public boolean isContain(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) { // data[i]和e都是类对象,equals()是值比较,比较两个对象的值是否相等。 ==是引用比较,比较变量名区域所放的值是否相等。
return true;
}
}
return false;
}
// 查询数组中元素e所在的索引,如果不存在元素e,则返回-1
public int find(E e) {
for (int i = 0; i < size; i++) {
if (data[i].equals(e)) { // data[i]和e都是类对象,equals()是值比较,比较两个对象的值是否相等。 ==是引用比较,比较变量名区域所放的值是否相等。
return i;
}
}
return -1;
}
// 新建扩容数组,把原数组中数据逐个挪入新数组中,实现动态数组
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity];
for (int i=0; i<size; i++) {
newData[i] = data[i];
}
data = newData;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("Array: size=%d, capacity=%d\n", size, data.length));
res.append('[');
for (int i = 0; i < size; i++) {
res.append(data[i]);
if (i != size - 1) {
res.append(", ");
}
}
res.append(']');
return res.toString();
}
}
动态数组实现栈(可以使用java.util.Stack代替):
接口:
package com.algorithm.stack;
public interface Stack<E> {
int getSize();
boolean isEmpty();
void push(E e); // 入栈
E pop(); // 出栈
E peek(); // 获取栈顶元素
}
实现接口:
package com.algorithm.stack.arraystack;
import com.algorithm.array.Array;
import com.algorithm.stack.Stack;
public class ArrayStack<E> implements Stack<E> {
Array<E> array; // 动态数组Array,capacity任意
public ArrayStack() {
array = new Array<>();
}
public ArrayStack(int capacity) {
array = new Array<>(capacity);
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
// getCapacity()是动态数组Array实现Stack所特有的,Stack本身没有该方法。因为只有动态数组才有capacity这一概念
public int getCapacity() {
return array.getCapacity();
}
@Override
// 入栈
public void push(E e) {
array.addLast(e);
}
@Override
// 出栈
public E pop() {
return array.deleteLast();
}
@Override
// 获取栈顶元素
public E peek() {
return array.getLast(); // 判断栈是否为空的逻辑在Array中
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Stack: ");
res.append("[");
for(int i = 0; i<array.getSize(); i++) {
res.append(array.get(i));
if (i != array.getSize()-1)
res.append(", ");
}
res.append("] top");
return res.toString();
}
}
动态数组实现队列(可以使用java.util.Queue代替):
接口:
package com.algorithm.queue;
public interface Queue<E> {
int getSize();
boolean isEmpty();
void enqueue(E e); // 入队
E dequeue(); // 出队
E getFront(); // 获取队首元素
}
实现接口:
package com.algorithm.queue.arrayqueue;
import com.algorithm.array.Array;
import com.algorithm.queue.Queue;
public class ArrayQueue<E> implements Queue<E> {
private Array<E> array;
// 构造方法
public ArrayQueue() {
array = new Array<>();
}
public ArrayQueue(int capacity) {
array = new Array<>(capacity);
}
@Override
public int getSize() {
return array.getSize();
}
@Override
public boolean isEmpty() {
return array.isEmpty();
}
@Override
// 入队
public void enqueue(E e) {
array.addLast(e);
}
@Override
// 出队
public E dequeue() {
return array.deleteFirst();
}
@Override
// 获取队首元素
public E getFront() {
return array.get(0); // 判断栈是否为空的逻辑在Array中
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: ");
res.append("front [");
for (int i=0; i<array.getSize(); i++) {
res.append(array.get(i));
if (i != array.getSize()-1) {
res.append(", ");
}
}
res.append("] tail");
return res.toString();
}
}
中缀表达式转后缀表达式
源码:
package com.algorithm.stack.problems.infixexpstopostfixexps;
import com.algorithm.array.Array;
import com.algorithm.queue.arrayqueue.ArrayQueue;
import com.algorithm.stack.arraystack.ArrayStack;
// convert infix expression to a postfix expression
public class InfixExpsToPostfixExps {
Array<ArrayQueue<Character>> infixArray = new Array<>(); // 中缀式字符串队列集合,infixArray每个元素都是一个队列。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
// 中缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
public void inputStr(String str) {
int count = 0; // 记录第几个infixArray元素将要存储,即第几个队列将要进行存储
infixArray.addLast(new ArrayQueue());
boolean isContinuousOperator = false; // 锁,防止多个操作符连续出现导致infixArray中有空元素出现
for (int i=0; i<str.length(); i++) {
char c = str.charAt(i);
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')') {
if (isContinuousOperator != true) {
count++;
infixArray.addLast(new ArrayQueue());
}
infixArray.get(count).enqueue(c);
count++;
infixArray.addLast(new ArrayQueue());
isContinuousOperator = true; // 加入了操作符,加锁
continue;
}
infixArray.get(count).enqueue(c);
isContinuousOperator = false; // 加入了操作数,解锁
}
// 输入是操作符后,操作符本身占了一个infixArray元素,此外infixArray中必定还会多加一个元素。防止因为最后一次输入是操作符,导致infixArray中最后一个元素为空
if (isContinuousOperator == true) {
infixArray.deleteLast();
}
}
// 显示中缀式字符串队列集合infixArray中储存的元素
public void outputInfixArray() {
System.out.println(infixArray);
}
// 测试"中缀式字符串使用队列储存"的效果
public void testOutputInfixArray() {
InfixExpsToPostfixExps infixExpsToPostfixExps = new InfixExpsToPostfixExps();
infixExpsToPostfixExps.inputStr("6789+2*(679*(3-1*345+1))");
infixExpsToPostfixExps.outputInfixArray();
}
StringBuilder postfixExpsBuilder = new StringBuilder(); // 后缀表达式字符串构建器
ArrayStack<Character> postfixArrayStack = new ArrayStack<>(); // 储存操作符的栈
Array<ArrayQueue<Character>> postfixArray = new Array<>(); // 可以理解为postfixExpsBuilder的记录器。postfixArray每个元素都是一个队列。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列。后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
/**
* 中缀转化为后缀表达式
* 1.按次序读取中缀表达式的字符。
* 2.读到一个操作数的时候,立即放入到输出中。
* 3.从栈顶到第一个优先级不大于(小于,低于或等于)它的运算符(或 '(',但优先满足前一个条件)之间的运算符加入后缀表达式中,该运算符再入栈
* 通俗理解:设预设操作符为'+', '-', '*', '/'。
* 设读取为'*',开始检测操作符栈顶是「同级或更高运算级符号」or「比自己低级的运算级符号」
* 如果遇到「同级或更高运算级符号」,例如'*'或'/',则将此「同级或更高运算级符号」赶出栈
* 如果遇到「同级或更高运算级符号」,例如'*'或'/',则将此「同级或更高运算级符号」赶出栈
* 如果遇到「同级或更高运算级符号」,例如'*'或'/',则将此「同级或更高运算级符号」赶出栈...
* 每次赶出操作符后检测是否操作符栈为空,为空栈则将自己压入栈,停止检测
* 每次检测中,如果遇到了'(',则将'('保留,自己进栈
* 如果遇到「比自己低级的运算级符号」,例如'+'或'-',则将此「比自己低级的运算级符号」保留,自己入栈,停止检测
* 设读取为'+',开始检测操作符栈顶是「同级或更高运算级符号」or「比自己低级的运算级符号」
* 如果遇到「同级或更高运算级符号」,例如'+'或'-',则将此「同级或更高运算级符号」赶出栈
* 如果遇到「同级或更高运算级符号」,例如'+'或'-',则将此「同级或更高运算级符号」赶出栈
* 如果遇到「同级或更高运算级符号」,例如'+'或'-',则将此「同级或更高运算级符号」赶出栈...
* 每次赶出操作符后检测是否操作符栈为空,为空栈则将自己压入栈,停止检测
* 此处,由于预设操作符中运算级别最低的是'+', '-',没有比其更低的,所以'+', '-'会一直将栈中的操作符赶出去,直到遇到'('或空栈
* 如果遇到了'(',则将'('保留,自己进栈
* 如果遇到了空栈,则自己进栈
* 如果遇到「比自己低级的运算级符号」,例如'=='或'!=',则将此「比自己低级的运算级符号」保留,自己入栈,停止检测
* 4.读到操作符“)”,则从栈中弹出栈元素并输出,直到遇到第一个“(”为止。其中“(”不再添加到输出中,而是直接舍弃。
* 5.当输入为空时,把栈里的操作符全部依次弹出并输出。
*/
public void toPostfixExps() {
int count = 0; // 记录第几个postfixArray元素将要存储,即第几个队列将要进行存储
postfixArray.addLast(new ArrayQueue());
for (int i=0; i<infixArray.getSize(); i++) {
char frontElem = infixArray.get(i).getFront(); // 获取infixArray中的当前队列队首,用来做读取判断。除用作判断外,别无他用
if (frontElem != '+' && frontElem != '-' && frontElem != '*' && frontElem != '/' && frontElem != '(' && frontElem != ')') {
int myQueueSize = infixArray.get(i).getSize(); // 接下来的for循环过程中,infixArray.get(i).getSize()的值会改变,因此先记录下来
for (int j=0; j<myQueueSize; j++) {
postfixArray.get(count).enqueue(infixArray.get(i).getFront()); // 记录后缀表达式,后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
postfixExpsBuilder.append(infixArray.get(i).getFront()); // 输出后缀表达式到字符串到StringBuilder
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
}
count++;
postfixArray.addLast(new ArrayQueue());
} else if (frontElem == '(') {
postfixArrayStack.push(infixArray.get(i).getFront()); // 获取infixArray中的当前队列队首(其实当前队列中只有一个操作符'(')
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
} else if (frontElem == ')') {
infixArray.get(i).dequeue(); // 进入到')'分支,当前'('使命就此终结。infixArray中的当前队列出队,即'('出队
while (postfixArrayStack.peek() != '(') {
postfixArray.get(count).enqueue(postfixArrayStack.peek()); // 记录后缀表达式,后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
postfixExpsBuilder.append(postfixArrayStack.peek()); // 输出后缀表达式到字符串到StringBuilder
postfixArrayStack.pop();
count++;
postfixArray.addLast(new ArrayQueue());
}
postfixArrayStack.pop(); // 发现postfixArrayStack中的'(',将其出栈
} else if (frontElem == '*' || frontElem == '/') {
// 读到操作符“+”,“-”,“*”,“/”,则从栈中弹出栈元素并输出,直到遇到优先级更低或者“(”的为止操作符为止。读取到的该运算符再入栈
// 判断栈是否为空,若为空,则直接把'*'或'/'压入栈中。没有此步判空会导致后面的postfixArrayStack.peek()报异常
if (postfixArrayStack.isEmpty()) {
postfixArrayStack.push(infixArray.get(i).getFront());
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
continue;
}
while (postfixArrayStack.peek() != '+' && postfixArrayStack.peek() != '-' && postfixArrayStack.peek() != '(') {
postfixArray.get(count).enqueue(postfixArrayStack.peek()); // 记录后缀表达式,后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
postfixExpsBuilder.append(postfixArrayStack.peek()); // 输出后缀表达式到字符串到StringBuilder
postfixArrayStack.pop(); // 栈顶元素出栈
count++;
postfixArray.addLast(new ArrayQueue());
// 检测逻辑会不断取栈顶检测,但如果栈中没有( 或 '+' 或'-',会取空栈的栈顶,显然空栈是没有栈顶的,会报异常。因此每次从栈中赶出一个操作符,都要检测一下是否为空栈
if (postfixArrayStack.isEmpty()) {
break;
}
}
postfixArrayStack.push(infixArray.get(i).getFront());
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
} else if (frontElem == '+' || frontElem == '-') {
// 读到操作符“+”,“-”,“*”,“/”,则从栈中弹出栈元素并输出,直到遇到优先级更低或者“(”的为止操作符为止。读取到的该运算符再入栈
// 通俗解释:如果出现'+'或'-',一直把栈中操作符赶出去,直到遇到'('为止,不会把'('赶出去
// 判断栈是否为空,若为空,则直接把'+'或'-'压入栈中。没有此步判空会导致后面的postfixArrayStack.peek()报异常
if (postfixArrayStack.isEmpty()) {
postfixArrayStack.push(infixArray.get(i).getFront());
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
continue;
}
while (postfixArrayStack.peek() != '(') {
postfixArray.get(count).enqueue(postfixArrayStack.peek()); // 记录后缀表达式,后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
postfixExpsBuilder.append(postfixArrayStack.peek()); // 输出后缀表达式到字符串到StringBuilder
postfixArrayStack.pop(); // 栈顶元素出栈
count++;
postfixArray.addLast(new ArrayQueue());
// 如果读取为'+'或'-',一直把栈中操作符赶出去,直到遇到'('为止,不会把'('赶出去
// 上述逻辑会不断取栈顶检测,但如果栈中没有(,会取空栈的栈顶,显然空栈是没有栈顶的,会报异常。因此每次从栈中赶出一个操作符,都要检测一下是否为空栈
if (postfixArrayStack.isEmpty()) {
break;
}
}
postfixArrayStack.push(infixArray.get(i).getFront());
infixArray.get(i).dequeue(); // infixArray中的当前队列出队
}
}
// 当结束读取时,把栈里的操作符全部依次弹出并输出
while (!postfixArrayStack.isEmpty()) {
postfixArray.get(count).enqueue(postfixArrayStack.peek()); // 记录后缀表达式,后缀式字符串使用队列储存,以处理多位操作数。原则上 一个操作数/一个操作符/一个'('或')' 占用一个队列
postfixExpsBuilder.append(postfixArrayStack.peek()); // 输出后缀表达式到字符串到StringBuilder
postfixArrayStack.pop(); // 栈顶元素出栈
count++;
postfixArray.addLast(new ArrayQueue());
}
}
// 打印中缀式字符串存储队列集合,打印后缀表达式postfixExps, 后缀表达式记录器postfixArray, 后缀栈postfixArrayStack
public void printPostfixExps() {
String postfixExps = postfixExpsBuilder.toString();
System.out.println("后缀表达式为:");
System.out.println(postfixExps);
// System.out.println("中缀式字符串存储队列集合为:");
// System.out.println(infixArray); // 打印中缀式字符串存储队列集合,查看是否全部出队
System.out.println("后缀表达式的存储队列集合为:");
System.out.println(postfixArray); // 打印后缀表达式的存储队列集合postfixArray
// System.out.println(postfixArrayStack);
}
ArrayStack<Double> operandStack = new ArrayStack<>(); // 操作数栈
/**
* 后缀表达式求值
* 1.按次序读取后缀表达式的每一个字符。
* 2.读取到操作数时,把操作数压入栈中。
* 3.读取到操作符时,对栈顶的2个操作数做相应运算,要注意操作数的前后顺序。结果压入栈中。
* 4.读取完所有的字符后,弹出栈。得到的值就是所求结果。
* @return
*/
public double calcPostfixExps() {
for (int i=0; i<postfixArray.getSize()-1; i++) {
char frontElem = postfixArray.get(i).getFront(); // 获取postfixArray中的当前队列队首,用来做读取判断。除用作判断外,别无他用
if (frontElem != '+' && frontElem != '-' && frontElem != '*' && frontElem != '/') {
int myQueueSize = postfixArray.get(i).getSize(); // 接下来的for循环过程中,infixArray.get(i).getSize()的值会改变,因此先记录下来
double myNumber = 0; // 记录当前多位操作数数值
for (int j=0; j<myQueueSize; j++) {
int myOperand = postfixArray.get(i).dequeue() - '0';
myNumber += myOperand * Math.pow(10, ((double)myQueueSize-j-1));
}
operandStack.push(myNumber); // 操作数入栈
// System.out.println(operandStack); // 打印操作数栈,展示后缀表达式运算过程第一处。第一处在207行 ,第二处在226行,第三处在230行
} else {
double a = operandStack.pop();
char operator = postfixArray.get(i).getFront(); // 获取操作符
postfixArray.get(i).dequeue(); // 操作符出队列,给下个操作符腾空间
double b = operandStack.pop();
double myRes = 0;
if (operator == '+') {
myRes = b + a;
} else if (operator == '-') {
myRes = b - a;
} else if (operator == '*') {
myRes = b * a;
} else if (operator == '/'){
myRes = b / a;
}
operandStack.push(myRes);
// System.out.println(operandStack); // 打印操作数栈,展示后缀表达式运算过程第二处。第一处在207行 ,第二处在226行,第三处在230行
}
}
// System.out.println(operandStack); // 打印操作数栈,展示后缀表达式运算过程第三处。第一处在207行 ,第二处在226行,第三处在230行
return operandStack.pop();
}
}
测试运行效果:
package com.algorithm.stack.problems.infixexpstopostfixexps;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
InfixExpsToPostfixExps infixExpsToPostfixExps = new InfixExpsToPostfixExps();
Scanner input = new Scanner(System.in);
// // 测试"中缀式字符串使用队列储存"的效果
// infixExpsToPostfixExps.testOutputInfixArray();
// // 预设输入测试区
// // infixExpsToPostfixExps.inputStr("6789+2*(3*(3-1*2+1))");
// // infixExpsToPostfixExps.inputStr("5+2*(3*(3-1*2+1))");
// infixExpsToPostfixExps.inputStr("670+9*3");
// 手动输入区
System.out.print("请输入一行中缀式运算符(操作数位数任意,可选操作符为'+', '-', '*', '/'):");
String inputStr = input.nextLine();
infixExpsToPostfixExps.inputStr(inputStr);
// 执行区
// System.out.println("中缀表达式字符串存储集合为");
// infixExpsToPostfixExps.outputInfixArray(); // 打印中缀式字符串存储队列集合
infixExpsToPostfixExps.toPostfixExps(); // 转化为后缀表达式
System.out.println("----------------------------");
infixExpsToPostfixExps.printPostfixExps(); // 打印后缀表达式postfixExps, 后缀表达式记录器postfixArray, 后缀栈postfixArrayStack,可选择打印。
System.out.println("----------------------------");
double res = infixExpsToPostfixExps.calcPostfixExps(); // 计算后缀表达式
System.out.println("后缀表达式运算结果为:" + res);
}
}