1.前言
中缀表达式和后缀表达式的概念在此不做赘述,只需记住中缀一般是人类习惯表达,即运算符在数中间,后缀是数在前,运算符在后即可
2.中缀转为后缀过程
- 遇到操作数。直接加入后缀表达式
- 遇到界限符。(入栈,遇到)则一次弹出栈内运算符并加入后缀表达式,直到弹出(为止
- 遇到运算符,依次弹出优先级等于或高于当前运算符的所有运算符,加入后缀表达式。若碰到(或栈空为止,再把当前运算符入栈
3.栈实现后缀表达式的计算流程
- 扫描后缀表达式
- 若操作数则压入栈,并继续扫描
- 若运算符则弹出栈顶两个元素,执行计算并将结果压入栈,执行
注意后缀表达式在栈中先弹出的是右操作数
4.一道leetcode后缀习题
class Solution {
public int evalRPN(String[] tokens) {
//用LinkedList实现存储数的栈
LinkedList<Integer> stackNumber = new LinkedList();
//如果是数字直接压入栈,否则弹出两个操作数进行计算
for(int i=0;i<tokens.length;i++){
//判断是否为数
if(!tokens[i].equals("+")&&!tokens[i].equals("-")&&!tokens[i].equals("*")&&!tokens[i].equals("/")){
stackNumber.push(Integer.parseInt(tokens[i]));
}else{
int b = stackNumber.pop();//右操作数
int a = stackNumber.pop();//左操作数
int temp =getValue(a,b,tokens[i]);
stackNumber.push(temp);
}
}
return stackNumber.pop();
}
//计算
public int getValue(int a,int b,String oper){
if(oper.equals("+")){
return a+b;
}else if(oper.equals("-")){
return a-b;
}else if(oper.equals("*")){
return a*b;
}else if(oper.equals("/")){
return a/b;
}
return 0;
}
}
5.开始实现
设计一个计算器,可以加减乘除,并注意符号运算优先级
思路:
1.将中缀表达式改为后缀表达式
2.将后缀表达式用栈实现
注意:本题不涉及()[]{}等情况,只是单纯数字和加减乘除符号 且输入的int数字会被下截断为int
总代码放到后面。现在逐部分分析
1.获取中缀表达式
- 通过控制台输入数据
- 考虑到数据输入可能有空格,故使用nextLine()方法
- 去除空格,使用replaceAll(" +“,”“),注意加号前面有空格,或者直接replaceAll(” “,”")(方法在nextLine()时不需要,了解即可)
- 本实现只是简单加减乘除,所以需要逐个检查是否有意外字符
- 对检查后的字符串进行分割
- str.split(“(?<=。)|(?=。)”),每个分隔符单独作为一项(包括分隔符)
\\+|-|\\*|/
表示分割±*/但是+和*
需要转义- 如此便获得中缀表达式,即人输入的内容
2.中缀转后缀
过程在第二部分有说明:
- 遇到操作数。直接加入后缀表达式
- 遇到界限符。(入栈,遇到)则一次弹出栈内运算符并加入后缀表达式,直到弹出(为止
- 遇到运算符,依次弹出优先级等于或高于当前运算符的所有运算符,加入后缀表达式。若碰到(或栈空为止,再把当前运算符入栈
由于本题目简单,不需要考虑括号
3.处理优先级问题
操作符合有优先顺序,当前的运算符,入栈前要判断,栈必须依次弹出优先级等于或高于当前运算符的所有运算符,加入进入后缀表达式
4.代码和注释
import java.util.*;
/**
* 设计一个计算器,可以加减乘除,并注意符号运算优先级
* 思路:1.将中缀表达式改为后缀表达式
* 2.将后缀表达式用栈实现
* 注意:本题不涉及()[]{}等情况,只是单纯数字和加减乘除符号 且输入的int数字会被下截断为int
*/
public class 计算器设计2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
//注意:如果使用next则会被空格中断,就是说空格后面的没取到,所以用nextLine()来获取以enter结尾
String input = sc.nextLine().replaceAll(" +","");//以防万一输入有问题,先去除空格
boolean ifOk = check(input);//检查输入是否只包括数字和+-*/
if(!ifOk) {
System.out.print("输入内容或者格式错误");
return;
}
//对输入的表达式用正则分割,包括分隔符
String[] exp = input.split("(?<=\\+|-|\\*|/)|(?=\\+|-|\\*|/)");
//输入的数据操作符数组转为后缀表达式
String[] out = infixExpression(exp);
//后缀表达式获取值
int value = evalRPN(out);
System.out.println(value);
}
//将中缀表达式转换为后缀表达式
public static String[] infixExpression(String[] exp) {
String[] res = new String[exp.length];//创建符合后缀表达式的字符串数组
String[] newInfixExp = new String[exp.length];
LinkedList<String> stack = new LinkedList();//创建一个操作符的栈,用于存储和弹出操作符
int index=0;//记录数组下标
for(int i=0,j=0;i<exp.length;i++) {
String temp = exp[i];
if(!temp.equals("+")&&!temp.equals("-")&&!temp.equals("*")&&!temp.equals("/")){
res[j]=temp;
j++;
index =j;
}else {
//根据优先级判断是否需要弹出运算符,时刻注意是否出现栈空情况
while(!stack.isEmpty()&&priority(temp)<=priority(stack.peek())) {
res[j]=stack.pop();
j++;
index =j;
}
stack.push(temp);
}
}
//最后将栈中所有操作符放入表达式中
while(!stack.isEmpty()) {
res[index]=stack.pop();
index++;
}
return res;
}
//对后缀表达式进行处理,tokens为以字符串为元素的后缀表达式各个操作数或操作符号:例如:tokens = ["2","1","+","3","*"]
public static int evalRPN(String[] tokens) {
LinkedList<Integer> stackNumber = new LinkedList();
//如果是数字直接压入栈,否则弹出两个操作数进行计算
for(int i=0;i<tokens.length;i++){
if(!tokens[i].equals("+")&&!tokens[i].equals("-")&&!tokens[i].equals("*")&&!tokens[i].equals("/")){
stackNumber.push(Integer.parseInt(tokens[i]));
}else{
int b = stackNumber.pop();//右操作数
int a = stackNumber.pop();//左操作数
int temp =getValue(a,b,tokens[i]);
stackNumber.push(temp);
}
}
return stackNumber.pop();
}
//计算
public static int getValue(int a,int b,String oper){
if(oper.equals("+")){
return a+b;
}else if(oper.equals("-")){
return a-b;
}else if(oper.equals("*")){
return a*b;
}else if(oper.equals("/")){
return a/b;
}
return 0;
}
//检查输入
public static boolean check(String input) {
char[] arr = input.toCharArray();
for(int i=0;i<arr.length;i++) {
if(!(arr[i]=='1'||arr[i]=='2'||arr[i]=='3'||arr[i]=='4'||arr[i]=='5'||arr[i]=='6'||arr[i]=='7'||arr[i]=='8'||arr[i]=='9'||arr[i]=='0'||arr[i]=='+'||arr[i]=='-'||arr[i]=='*'||arr[i]=='/')) {
return false;
}
}
return true;
}
//处理加减乘除的优先级问题
public static int priority(String oper) {
if (oper.equals("*") || oper.equals("/")) {
return 1;
}else {
return 0;
}
}
}
运用截图:
综上,end;