即可就不说逆波兰的实现了,具体实现过程直接看《大话数据结构》即可
package algorithm.DataStruct.Stack;
import java.util.*;
/**
* @author: Serendipity
* Date: 2022/1/28 18:50
* 以下是几个关键点的总结:
* 1.使用 Map 作为运算符的优先级集合;
* 2.栈 Stack<Character>st 为操作符栈,负责存放操作符以及对操作符的一些排序操作;
* 3.队列 LinkedList<Character>list 为后缀队列;
* 4.基本的代码逻辑为:
* 4.1.如果为数字,直接进队列;
* 4.2.如果栈顶元素为左括号或当前元素为左括号,直接压栈;
* 4.3.如果当前元素为右括号,进行(将栈顶元素弹出并存放到后缀队列中)的操作,一直到栈顶元素
* 为左括号时为止,并注意要将左括号也弹出;
* 4.4.如果栈顶元素的优先级小于等于当前元素的优先级,将当前元素压栈;否则,将栈顶元素
* 依次弹栈知道栈顶元素的优先级不大于当前元素的优先级为止;
* 4.5.操作完成后,将栈依次弹出入队;
* 注:不能开头是负号
*/
public class SuffixExpression {
public static void main(String[] args) {
System.out.println("请输入一个中缀表达式,开头不要带负号");
Scanner in = new Scanner(System.in);
List<String> list = strToList(in.nextLine());
System.out.println("你输入的中缀表达式的符号为:" + list);
List<String> change = change(list);
System.out.println(change);
System.out.printf("%4f", calculateExpression(change));
}
public static List<String> getListString(String expression) {
String[] s = expression.split(" ");
List<String> list = new ArrayList<>();
for (String s1 : s) {
list.add(s1);
}
return list;
}
//使用后缀表达式的方法读取栈内元素并且进行操作
public static double calculateExpression(List<String> list) {
double result = 0.0;
Stack<String> stack = new Stack<>();
for (String item : list) {
if (item.matches("\\d+")) {//匹配的是多位数
stack.push(item);
} else {//后缀表达式要求'-'与'/'都是 次栈顶元素减去(-)或除(/)栈顶元素
double num2 = (double) Double.parseDouble(stack.pop()); //栈顶元素
double num1 = (double) Double.parseDouble(stack.pop()); //次栈顶元素
switch (item) {
case "+" -> {
result = num1 + num2;
break;
}
case "-" -> {
result = num1 - num2;
break;
}
case "*" -> {
result = num1 * num2;
break;
}
case "/" -> {
result = num1 / num2; //num1 / num2 num1次栈顶 num2栈顶
break;
}
default -> {
throw new RuntimeException("运算符有误");
}
}
stack.push("" + result);
}
}
return Double.parseDouble(stack.pop());
}
/*
将中缀表达式转换为后缀表达式
1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:使用peek可以看栈顶元素
1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
5)遇到括号时:
(1)如果是左括号“(”,则直接压入s1
(2)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6)重复步骤1至5,直到表达式的最右边
7)将s1中剩余的运算符依次弹出并压入 s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
*/
public static List<String> change(List<String> list) {
Stack<String> operStack = new Stack<>(); //运算符栈
List<String> outList = new ArrayList<>(); //存储中间结果的栈直接用list即可,因为我们一直只往里面存值
for (String s : list) {
if (isNumber(s)) { //数字直接入栈
// if(s.matches("\\d+")){ //使用正则表达式判断是数字
outList.add(s);
} else if (s.equals("(")) { //左括号直接入符号栈
operStack.push(s);
} else if (s.equals(")")) { //右括号一直出栈直到遇到左括号
while (!operStack.peek().equals("(")) { //peek是stack栈特有的偷看效果 能查看最上面的元素 stream流也有但是效果不一样
outList.add(operStack.pop());
}
operStack.pop(); //符号栈出栈 把遇到的 ( 也出栈 这样符号栈内就没有 ( ) 了
} else {//是符号则需要判断优先级
while ((operStack.size() != 0) && getPriority(operStack.peek()) >= getPriority(s)) {
outList.add(operStack.pop());
}
operStack.push(s);
}
}//之后如果没有继续需要比较的元素了
while (!operStack.empty()) { //直接将符号栈内的所有元素直接添加到输出栈即可
outList.add(operStack.pop());
}
return outList;
}
//该函数用于将输入的字符串中的所有数据转换为单个字符以便转换为后缀表达式
public static List<String> strToList(String expression) {
int index = 0;
char ch = ' ';
StringBuilder sb = null;
List<String> list = new ArrayList<>();
while (index < expression.length()) {
ch = expression.charAt(index);
if (isOper(ch)) {//是符号直接进入List
list.add("" + ch);
index++;
} else {//是数字
sb = new StringBuilder();
// while(isNumber(ch)){
// sb.append(ch);
// index++;
// if(index>=expression.length()){
// break;
// }
// ch=expression.charAt(index);
while (index < expression.length() && isNumber(ch = expression.charAt(index))) {
sb.append(ch);
index++;
}
list.add(sb.toString());
}
}
return list;
}
public static boolean isNumber(char num) {
return num <= 57 && num >= 48;
}
public static boolean isOper(char oper) {
return oper == '+' || oper == '-'
|| oper == '*' || oper == '/'
|| oper == '(' || oper == ')';
}
public static boolean isNumber(String num) {
return !(num.equals("+") || num.equals("-")
|| num.equals("*") || num.equals("/")
|| num.equals(")") || num.equals("("));
}
public static boolean isBracket(String str) {
return str.equals("(") || str.equals(")");
}
public static int getPriority(String str) {
Map<String, Integer> map = new HashMap<>();
map.put("+", 1);
map.put("-", 1);
map.put("*", 2);
map.put("/", 2);
return map.get(str) == null ? 0 : map.get(str);
}
}