//利用堆栈计算后缀表达式
//定义正则,判断是否是数字或者小数点
private final Pattern pattern = Pattern.compile("[0-9.]*");
@Test
public void test() {
String formula_began = "11.1-(2.2/3.3)+(9.9*8.8/(7.7-(6.6*5.5+4.4)))";
String formula_after[] = conversion(formula_began);
System.out.println(Arrays.toString(formula_after));
Stack<String> stack = new Stack<>();
for (int i=0;i<formula_after.length;i++) {
//判断当前拿到得字符是否是数字或小数点
if (pattern.matcher(formula_after[i]).matches()) {
stack.push(formula_after[i]);
}else {
stack.push(TemperatureCalculator(stack.pop(),stack.pop(),formula_after[i]));
}
}
System.out.println(stack.peek());
}
/**
* 转换中缀表达式为后缀表达式
*/
public String[] conversion(String formula_began) {
//先将字符串打断成字符集合
List<String> formula_after = new ArrayList<>();
for (int i=0;i<formula_began.length();i++) {
formula_after.add(formula_began.charAt(i) + "");
}
//存储数字
Stack<String> stack = new Stack<>();
//存储符号
Stack<String> kcats = new Stack<>();
//times是用来计算有多少运算符的
int times = 0;
//以下代码中,你将会看到每次times改变后time才改变,可以用这两个值不同的判断来区分当前读取的字符是新字符串的开始(不止个位的数字)
// 还是旧字符串的拼接
int time = 0;
//siz这里主要是用来做栈的大小,由于for循环中直接用xx.size()做判断,代码中又对栈做pop(),会导致数值不确定
int siz = 0;
for (int i=0;i<formula_after.size();i++) {
//判断当前拿到得字符是否是数字或小数点
if (pattern.matcher(formula_after.get(i)).matches()) {
//如果当前是第一个,没有必要合并字符串
if (i == 0) {
stack.push(formula_after.get(i));
}else {
//判断是否读到了运算符,如果times改变,说明读完了一个完整的数,接下来的继续读,开始合并下一个数
if (times != time) {
stack.push(formula_after.get(i));
time = times;
//否则开始合并下一个数
}else {
stack.push(stack.pop() + formula_after.get(i));
}
}
//不是数字时需要考虑字符类型,然后入符号栈或者出符号栈压入数字栈
}else {
//如果遇到右括号,直接输出存储符号栈中的所有,直到遇到左括号停止,并将左括号抛出
// (抛出后需要break跳出,否则可能导致左括号前的符号在此时也出栈)
if (formula_after.get(i).equals(")")) {
siz = kcats.size();
for (int j=0;j<siz;j++) {
if (!kcats.peek().equals("(")) {
stack.push(kcats.pop());
}else {
kcats.pop();
break;
}
}
//如果符号是+或者-,那么需要将之前的所有符号输出,直到遇到左括号或者输出完毕停止,这里用到一个规则
// (每读到一个符号,需要输出优先级比他高的其他符号,直到一个比他低的或者左括号停止,我觉得这里应该补上或者输出完毕)
}else if (formula_after.get(i).equals("+") || formula_after.get(i).equals("-")) {
if (kcats.size() != 0) {
siz = kcats.size();
for (int j=0;j<siz;j++) {
if (!kcats.peek().equals("(")) {
stack.push(kcats.pop());
}else {
break;
}
}
}
//这里为什么放在for循环以及if外,以下是放在else if下一行代码时的假设
// 11-(22*33)+44,当读到+号时,stack中是112233*,kcats中是-,然后执行完代码后,它先将+放入符号栈,再通过for循环提出
// 最后输出结果为112233*+44-这与正确结果112233*-44+不符,当初写到这里的时候让我想了很久,所以记录下来
kcats.push(formula_after.get(i));
times ++;
//这里同上一个规则一致
}else if (formula_after.get(i).equals("*") || formula_after.get(i).equals("/")) {
if (kcats.size() != 0) {
for (int j=0;j<kcats.size();j++) {
//这里一开始未对+-做判断,导致计算优先级一直出错
if (kcats.peek().equals("(") || kcats.peek().equals("+") || kcats.peek().equals("-")) {
break;
}else {
stack.push(kcats.pop());
}
}
}
kcats.push(formula_after.get(i));
times ++;
}else if (formula_after.get(i).equals("(")) {
kcats.push(formula_after.get(i));
times ++;
}
}
}
siz = kcats.size();
//如果符号栈中还有内容,直接压入数字栈中
for (int i=0;i<siz;i++) {
stack.push(kcats.pop());
}
//将数字栈中的内容倒序放入数组中
String[] formula = new String[stack.size()];
for (int i=formula.length-1;i>=0;i--) {
formula[i] = stack.pop();
}
return formula;
}
/**
* 通过c的类型来处理a,b之间的关系
*/
public String TemperatureCalculator(String a, String b, String c) {
String result;
if (c.equals("+")) {
result = (Double.parseDouble(b) + Double.parseDouble(a)) + "";
return result;
}else if (c.equals("-")) {
result = (Double.parseDouble(b) - Double.parseDouble(a)) + "";
return result;
}else if (c.equals("*")) {
result = (Double.parseDouble(b) * Double.parseDouble(a)) + "";
return result;
}else if (c.equals("/")) {
result = (Double.parseDouble(b) / Double.parseDouble(a)) + "";
return result;
}
return null;
}
个人觉得代码有点混乱,如果有更好的思路或者代码,欢迎留言,如果你能看到这里,谢谢你的观看!