import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class methon {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("欢迎使用计算器!");
System.out.println("要计算的式子:-->例如: 1+((2+3)*4)-5 ");
String str = in.nextLine();
//将中缀转换后缀表达式
//先将字符串转换为中缀 放入List
String expression =str;
System.out.println(expression);
//先将String转换为中缀表达式 存储到list
List<String>s1 = ConvertList(expression);
System.out.println(s1);
//将存储到List中的中缀表达式(prefix) 变为 后缀表达式 (suffix)
List<String> s2 =PrefixConverSuffix(s1);
System.out.println(s2);
//调用后缀表达式计算方法进行计算(Calculate)
int result = Calculate(s2);
System.out.println(result);
//先定义一个逆波兰表达式
/* String ni = "4 5 * 8 - 60 + 8 2 / +";
List<String> list1 = get(ni);
System.out.println(list1);
int f = calculate(list1);
System.out.println(f);*/
}
//最初的 自己导入后缀表达式 将他转为List
public static List<String> get(String ni){
String[] k = ni.split(" ");
List<String> list = new ArrayList<>();
for (String s:k
) {
list.add(s);
}
return list;
}
//将中缀转为List
public static List<String> ConvertList(String s){
List<String> list = new ArrayList();
int i = 0;//指针 用于遍历字符串
String str; //多位数拼接
char c;
do{
if((c = s.charAt(i))<48||(c = s.charAt(i))>57){ //每次都会赋值新的c 不用置空
list.add(""+c);
i++;
}else{ //考虑多位数
str = ""; //将str置空防止下一次拼接使用了上一次的字符
while(i<s.length() && (c=s.charAt(i))>=48 && (c=s.charAt(i))<=57){
str +=c;
i++;
}
list.add(str);
}
}while(i<s.length());
return list;
}
//将中缀的List 变为 后缀的list
public static List<String> PrefixConverSuffix(List<String> list){
Stack<String> s1 = new Stack<>(); //符号栈
Stack<String> s2 = new Stack<>(); //储存栈
//遍历list
for (String item: list) {
//如果是一个数 就入栈
if(item.matches("\\d+")){
s2.push(item);
}else if(item.equals("(")){
s1.push(item);
}else if(item.equals(")")){
while(!s1.peek().equals("(")){
s2.push(s1.pop());
}
s1.pop(); //将他弹出 使top下移动
}else{
//当s1 栈顶元素优先级比将要入栈的符号优先级高时 先将栈顶弹出再将当前符号入栈 (while更方便)
while(s1.size()!=0&&(Priority(s1.peek())>=Priority(item))){
s2.push(s1.pop());
}
s1.push(item);
}
}
//完成遍历后将符号栈元素全部弹出到储存栈中去
while(!s1.empty()){
s2.push(s1.pop());
}
return s2;
}
//比较符号的优先级
public static int Priority(String s){
int value = 0;
switch (s){
case "+":
case "-":
value = 1;
break;
case "*":
case "/":
value = 2;
break;
default:
/*System.out.println("不存在");*/
//会报出几处正常的不存在问题
break;
}
return value;
}
//将后缀表达式进行计算
public static int Calculate(List<String> list){
Stack<String> stack= new Stack<>();
for (String k:list
) {
if(k.matches("\\d+")){ //正则表达式
stack.push(k);
}else{
//pop出两个数 运算 在入栈
int num2 = Integer.parseInt(stack.pop());
int num1 = Integer.parseInt(stack.pop());
//都是用后弹出的数去操作先弹出的数 和栈的性质有关 (先进后出)
int res = 0;
if(k.equals("+")){
res = num2+num1;
}else if(k.equals("-")){
res = num1 - num2;
}else if(k.equals("*")){
res = num1 * num2;
}else if(k.equals("/")){
res = num1 / num2;
}else{
throw new RuntimeException("运算符异常");
}
stack.push(res+"");
}
}
return Integer.parseInt(stack.pop());
}
}
另附知识:
- 正则表达式的运用:matches("//d+")--> (+)表示多位数的判断;
- Integer.parseInt() Integer包装类的使用;
- 栈的结构:先进后出-->(为什么计算时要用后弹出操作先弹出)
- split()的使用: 这里-->
String[] k = ni.split(" "); //分割形式的练习
- ***试一试考虑加上空格、小数点的情况***