package com.yg.stack;/*
@author GeQiLin
@date 2020/2/22 20:24
*/
import org.hibernate.validator.internal.util.privilegedactions.NewProxyInstance;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/*
* 求解逆波兰表达式
* */
public class PolandNotation {
public static void main(String[] args) {
/*
//计算后续表达式
String lastExpersion = "1 2 + 5 * 6 -";
//将lastExpersion分解成单个字符并存入arraylist数组中
List<String> list = transferArrayList(lastExpersion);
//遍历list集合进行对应的计算操作
int res = 0;
res = calculator(list);
System.out.println(lastExpersion + "=" + res);*/
//中序转后序
String expersion = "1+((2+3)*4)-5";
List<String> infixExpersion = new ArrayList<>();
infixExpersion = toInfixExpersionList(expersion);
System.out.println("中缀表达式:"+infixExpersion);
List<String> suffixExpersion = new ArrayList<>();
suffixExpersion = parseSuffixExpersion(infixExpersion);
System.out.println("后缀表达式:"+suffixExpersion);
System.out.println("expersion="+calculator(suffixExpersion));
}
/*
将中序表达式的list转为后序表达式的list
准备一个栈s1,ArrayList集合s2
* 1.遍历中序表达式
2.如果是操作数直接入s2
3.如果是括号:
左括号(:直接入s1
右括号):将s1栈顶元素依次出栈然后放入s2直至栈顶为(为止
4.如果是操作符
s1为空则存入s1
栈顶值为(则如s1
否则
优先级如果大于栈顶运算符直接入s1
优先级如果小于等于栈顶运算符则将s1的栈顶运算符加到s2中然后再次进行4操作
* */
private static List<String> parseSuffixExpersion(List<String> list) {
Stack<String> s1 = new Stack<>();
List<String> s2 = new ArrayList<>();
for (String oper : list) {
if (oper.matches("\\d+")) {
//如果是操作数;
s2.add(oper);
} else if (oper.equals("(")) {
s1.push(oper);
} else if (oper.equals(")")) {
while (!s1.peek().equals("(")) {
s2.add(s1.pop());
}
s1.pop();//将"( "出栈
} else {
//是操作符,当oper的优先级大于栈顶时将oper加入s1,否者将s1栈顶出栈加入s2并循环判断
while (s1.size() != 0 && getPriority(s1.peek().charAt(0)) >= getPriority(oper.charAt(0))) {
s2.add(s1.pop());
}
s1.push(oper);
}
}
while (s1.size() != 0) {
s2.add(s1.pop());
}
return s2;
}
//进行逆波兰表达式的运算规则
//从左至右扫描逆波兰表达式
//1.如果是操作数就进栈
//2.如果是操作符,就将两个操作数出栈进行运算
private static int calculator(List<String> list) {
if (list == null) {
throw new RuntimeException("集合为空");
}
Stack<String> stack = new Stack<>();
for (String oper : list) {
//如果oper是操作数则入栈
if (oper.matches("\\d+")) {
stack.push(oper);
} else {
//oper是字符则将两个书pop出
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
int res = 0;
//实际计算操作
res = doCalculator(num1, num2, oper);
stack.push("" + res);
}
}
return Integer.parseInt(stack.pop());
}
//进行实际的计算处理
private static int doCalculator(int num1, int num2, String oper) {
char c = oper.charAt(0);
int res = 0;
switch (c) {
case '+':
res = num1 + num2;
break;
case '-':
res = num1 - num2;
break;
case '*':
res = num1 * num2;
break;
case '/':
if (num1 == 0) {
throw new RuntimeException("被除数不能为0");
}
res = num1 / num2;
break;
default:
System.out.println("参数有误");
break;
}
return res;
}
//将逆波兰表达式逐个存入list集合中
private static List transferArrayList(String lastExpersion) {
if (lastExpersion == "") {
System.out.println("逆波兰表达式为空!!");
return null;
}
String[] operArr = lastExpersion.split(" ");
//如果最后一位不是操作符而是操作数则表达式错误
if (operArr[operArr.length - 1].matches("\\d+")) {
throw new RuntimeException("逆波兰表达式有误,最后一位应该为操作符");
}
List<String> list = new ArrayList<String>();
for (String str : operArr) {
list.add(str);
}
return list;
}
//将中序表达式装入ArrayList中
public static List<String> toInfixExpersionList(String s) {
if (s == "") {
throw new RuntimeException("中序表达式不能为空!!");
}
int index = 0;//相当于一个指针用于遍历s
char oper = ' ';//用于存储s中index索引处的字符
List<String> list = new ArrayList<String>();
String str = "";//用于处理多位数
do {
if ((oper = s.charAt(index)) < 48 || (oper = s.charAt(index)) > 57) {
//当前字符是非数字
list.add("" + oper);
index++;
} else {
str = "";
//当前字符为操作数,要判断是不是多位数
while (index < s.length() && (oper = s.charAt(index)) >= 48 && (oper = s.charAt(index)) <= 57) {
str += oper;//拼接;
index++;
}
list.add(str);
}
} while (index < s.length());
return list;
}
//得到操作符的优先级
public static int getPriority(int ch) {
if (ch == '+' || ch == '-') {
return 0;
} else if (ch == '*' || ch == '/') {
return 1;
} else {
return -1;
}
}
}
栈实现中序表达式转后序表达式,并求出逆波兰表达式的值
最新推荐文章于 2022-04-30 22:37:38 发布