利用JAVA实现中缀表达式向后缀表达式的转换,并求出表达式的值

来源:互联网 发布:java 判断编码格式 编辑:程序博客网 时间:2024/05/16 06:47
/*

 * 计算表达式的值:利用表达式的后缀表达式来计算!

 */
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Stack;


public class MyClass {


public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
String str = sc.next();
String[] arr = check(str);
System.out.println(sumS(arr));
sc.close();
}


public static String[] check(String str) {
char[] arr = str.toCharArray();
StringBuilder sb = new StringBuilder();


// 创建自定义的栈对象
MYStack stkN = new MYStack();// 数字
MYStack stkM = new MYStack();// 符号


for (int i = 0; i < arr.length; i++) {
// 判断读取的字符如果是左括号,直接入栈
if (arr[i] == '(') {
stkM.push(arr[i] + "");
}
// 判断读取的字符如果是数字:如果是最后一个,就append到sb结尾,再入栈;
// 如果不是,就直接append到sb结尾
else if (Character.isDigit(arr[i])) {
if (i == arr.length - 1)
stkN.push(sb.append(arr[i] + "").toString());
else
sb.append(arr[i] + "");
}
// 判断读取的字符如果是操作符:就将该操作符与操作符栈顶的操作符比较优先级,如果读取的操作符优先级高
// 或者遇到栈底以及左括号就直接入栈,如果优先级不高于,则将栈顶的操作符弹出并压入到数字栈中,再从头重复操作;
else if (arr[i] == '+' || arr[i] == '-' || arr[i] == '*'
|| arr[i] == '/') {
// 因为读到一个操作符时,如果前面读到的数字sb不为空就可以入栈了。
// 当操作符前面有左括号时,数字sb为空,不能入栈,所以要进行判断
if (sb.length() != 0) {
stkN.push(sb.toString());
}
// 循环判断操作符的优先级以及特殊情况
while (true) {
if (!compare(stkM.getElement(), arr[i] + "")) {
if (stkM.getElement().equals("?")
|| stkM.getElement().equals("(")) {
stkM.push(arr[i] + "");
break;
} else {
stkN.push(stkM.pop());


}
} else {
stkM.push(arr[i] + "");
break;
}
}
// 经数字压入后,必须清空数字sb的内容,以便进行下一次操作
sb.delete(0, sb.length());
}
// 判断读取的字符如果是右括号:就依次将符号栈中的元素pop出来,并push到数字栈中
else {
// 下面两句代码是将之前读到的数字push到数字栈中,并清空sb的内容
stkN.push(sb.toString());
sb.delete(0, sb.length());
// 循环操作,将符号站的符号探春并压入到数字栈中,直到遇到左括号结束
while (!stkM.getElement().equals("(")) {
stkN.push(stkM.pop());
}
// 丢弃左括号
stkM.pop();
}
}


// 表达式读取完毕后,需要将符号栈中的内容读取到数字栈中
while (!stkM.getElement().equals("?")) {
stkN.push(stkM.pop());
}


// 将数字栈中的内容弹出逆序输出到一个字符串数组,方便参数的调用
// 在使用FOR循环是,发生ArrayIndexOutOfBoundsException;
// 理论上使用for绝对可以的
// len()方法是自定义栈获取栈的长度的方法
String[] strArray = new String[stkN.len()];
int len = stkN.len();
int i = 1;
while (!stkN.getElement().equals("?")) {
strArray[len - i] = stkN.pop();
i++;
}
return strArray;
}


// 返回值为真,直接入栈,判断运算符的优先级
// 只有当读取的字符是 * 或者 / 并且 栈顶的字符是 + 或者 - ,才返回真,也就是可以直接将操作符压入到操作符栈中
public static boolean compare(String str, String strE) {
if ((strE.equals("*") || strE.equals("/"))
&& (str.equals("+") || str.equals("-"))) {
return true;
}
return false;
}


// 利用后缀表达式求值:
// 总体思想是:先定义一个栈,顺序读取后缀表达式的字符串序列,如果是数字则压入到栈中,如果是操作符op,就在栈中pop出两个元素firstP,SecondP,
// 计算FirstP<op>Second的值,压入到栈中,直到后缀表达式读取完毕,栈顶的值就是表达式的计算结果
public static int sumS(String[] arr) {
// 初始化一个Integer泛型的栈
Stack<Integer> st = new Stack<Integer>();
// 循环读取后缀表达式的字符
for (int i = 0; i < arr.length; i++) {
// 正则匹配,如果是数字,返回真,并且转换成int压入到栈中
if (arr[i].matches("\\d+")) {
st.push(Integer.parseInt(arr[i]));
} else {
// 判断栈中的元素个数是否大于1个,只有大于一个时,才能取出两个元素
// 如果不满足,就在栈底添加一个int值:0
if (st.size() < 2)
st.add(0, 0);
// 先POP出来的是右操作数,后POP出来的是左操作数
int rv = st.pop();
int lv = st.pop();
// 根绝对应的操作符,实现相应的算法
if (arr[i].equals("+")) {
st.push(lv + rv);
} else if (arr[i].equals("-")) {
st.push(lv - rv);
} else if (arr[i].equals("*")) {
st.push(lv * rv);
} else {
st.push((int) (lv / rv));
}
}
}
// 返回栈顶的元素,也就是后缀表达式的计算结果
return st.pop();
}
}


// 自定义栈,没有借助于Vector的Stack类,主要是考虑到运用的灵活性
class MYStack {
ArrayList<String> stack = new ArrayList<String>();


// 经测试,Put 和 Pop操作均能正常使用


// 入栈方法
public void push(String str) {
this.stack.add(str);
}


// 出栈方法
public String pop() {
if (!this.stack.isEmpty()) {
String str = this.stack.get(this.stack.size() - 1);
this.stack.remove(this.stack.size() - 1);
return str;
}
return null;


}


// 获取栈顶元素方法:类似于Vector.Stack的peek方法。
// 如果到达栈底,则返回"?",不返回NULL是因为在check()函数中需要将栈顶元素与表达式读取到的元素进行比较。
public String getElement() {
if (this.stack.size() > 0) {
String str = this.stack.get(this.stack.size() - 1);
return str;
} else
return "?";
}


// 获取栈的长度
public int len() {
return this.stack.size();
}


// 提供一个测试函数:遍历Stack.stack中的元素:
public void show() {
Iterator<String> it = this.stack.iterator();
while (it.hasNext()) {
System.out.print(it.next() + ",");
}
}
}
2 0
原创粉丝点击