java实现逆波兰计算器(支持小数和括号)

实现思路

  • 将表达式(String类型)存入集合中
  • 通过集合来将内容排列成逆波兰表达式的形式
  • 在通过逆波兰计算器来进行计算

辅助函数

//用于判断是不是运算符
public static boolean isOper(String str) {//字符串的比较用equals
        return "(".equals(str) || ")".equals(str) || "+".equals(str) || 
                 "-".equals(str)||"*".equals(str) || "/".equals(str);
}

-------------------------------------------------------------------------------
private static int ADD = 1;
private static int SUB = 1;
private static int MUL = 2;
private static int DIV = 2;

//获取运算符优先级
private static int getPriority(String str) {
    int result = 0;
    switch (str) {
        case "+":
            result = ADD;
            break;
        case "-":
            result = SUB;
            break;
        case "*":
            result = MUL;
            break;
        case "/":
            result = DIV;
            break;
        default:
            try {
                throw new RuntimeException("输入运算符错误");
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
    }
    return result;
}


-------------------------------------------------------------------------------

//计算方法,传入两个数据和运算符,可以得到相应的结果
static double operation(double num1, double num2, String str) {
    double result = 0;
    switch (str) {
        case "+":
            result = num1 + num2;
            break;
        case "-":
            result = num2 - num1;
            break;
        case "*":
            result = num2 * num1;
            break;
        case "/":
            result = num2 / num1;
            break;
        default:
            try {
                throw new RuntimeException("运算符输入错误");
            } catch (RuntimeException e) {
                e.printStackTrace();
            }
    }
    return result;
}

将表达式存入集合

//将expression存到ArrayList中
private static List<String> arraysOrder(String expression) {
    String str = "";        //用于组合数字
    int index = 0;            //用于标记扫描到表达式的哪个位置,也就是指向表达式的指针
    String ch = “”;        //用于接收扫描到的字符
    ArrayList<String> list = new ArrayList();          //创建一个list
    do {
        ch = expression.substring(index, index + 1);   //从表达式中读取一个字符
        if (isOper(ch)) {        //判断是不是运算符————辅助函数,文章前面有写
            list.add(ch);        //将运算符加入list
            index++;            //index后移一位
        } else {  //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
            do {
                ch = expression.substring(index, index + 1);    //读取一个字符
                str += ch;              //进行拼接
                index++;                //指针后移
                //不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
            } while ((index < expression.length()) && ((expression.charAt(index) <= 57 
                        && expression.charAt(index) >= 48) || '.' == expression.  
                        charAt(index)));
            list.add(str);            //将拼接的字符串录入到list
            str = "";                 //这里一定要将str置位初值!!!!!!!!
        }
    } while (index < expression.length());        //限制条件,读到表达式最后一位就停止
    return list;                    //返回list
}

转换成逆波兰顺序

中缀表达式——>逆波兰表达式(后缀表达式)

  • 创建一个String栈,用于存储运算符;创建一个list(String),用于存放生成的逆波兰表达式
  • 遍历前面得到的 中缀表达式的list 中的所有内容。
  • 遇到数字
    • 直接录入逆波兰list中
  • 遇到括号
    • 如果是左括号,就直接压入栈中
    • 如果是右括号,就依次弹出栈中的运算符,直至遇到右括号才停止,然后丢弃这一对括号
  • 遇到运算符
    • 如果是栈中第一个运算符(括号不是运算符),就直接压入栈中
    • 如果不是第一个运算符
      • 如果运算符的优先级大于栈顶运算符的,直接压入栈中
      • 如果运算符的优先级小于或等于栈顶运算符,将栈顶的运算符弹出到list中,然后继续和下一个下一个栈顶运算符比较——所以这里会用到循环

下面给出中缀表达式后缀表达式的代码

private static List reversalOrder(List<String> tempList) {        //传入前面得到的中缀表达式的list
    ArrayList list = new ArrayList();                //创建一个list,用来存储中间数据
    Stack<String> stack = new Stack<>();            //创建一个栈,用于存储运算符
    for (String str : tempList) {                    //增强for循环,遍历集合中的数据
        if (str.matches("\\d+") || str.matches("\\d+\\.\\d+")) {    //判断是数,或者是小数
            list.add(str);                           //将数据录入list
-------------------------------------------------------------------------------------
        } else {                                     //遇到运算符
            if ("(".equals(str)) {                   //如果是"(",就压入栈中
                stack.push(str);
            } else if (")".equals(str)) {            //如果遇到")",就依次弹出栈中的运算符到list中,遇到"("才停止,然后丢弃这一对括号
                while (true) {                    
                    if ("(".equals(stack.peek())) {        //遇到左括号
                        break;
                    }
                    list.add(stack.pop());            //将中间得到的运算符都录入到list中
                }
                stack.pop();                            //丢弃"("
-------------------------------------------------------------------------------------
            } else {                                    //遇到的是运算符
                while (true) {
                    if (stack.isEmpty() || "(".equals(stack.peek())) {        //判断栈是不是空,或者栈中是左括号。如果满足一个,就说明是目前栈中的第一个运算符
                        stack.push(str);                //运算符直接入栈
                        break;                          //出循环,遍历下一个元素
                    } else if (getPriority(stack.peek()) < getPriority(str)) {                            
          //如果运算符的优先级比栈顶运算符优先级高,就压入栈——辅助函数,文章前面有提供
                        stack.push(str);                //入栈
                        break;                          //出循环,遍历下一个元素
                    } else {
          //和栈顶运算符相比优先级相等或者小于,就将栈顶运算符弹出并录入list中,然后该运算符就和栈中新的栈顶元素相比较(循环)
                        list.add(stack.pop());
                    //调用pop之后,下次循环自然就是新的栈顶元素
                    }
                }
            }
        }
    }
    //将栈中的所有运算符全部弹出到list中
    while (!stack.isEmpty()) {
        list.add(stack.pop());
    }
    return list;            //返回后缀表达式
}

逆波兰计算器

思路

  • 创建一个栈,用于存储数字(这里是String类型)
  • 遍历逆波兰list
  • 遇到数字就入栈
  • 遇到运算符就从栈中弹出两个数字
  • 用后弹出的减去先弹出的(后缀表达式嘛,后面的减去前面的),再将结果压入栈中
public static double calculator(List<String> arr) {
    //从左到右,遇到数字就入栈,遇到运算符就弹出两个数据,然后:后弹出的-先弹出的,再将结果入栈
    Stack<String> stack = new Stack<String>();    //创建栈,用于存储数字
    double num1;                            //用于接收弹出的数字
    double num2;                            //用于接收弹出的数字
    String ret;                             //用于接收运算符
    for (String str : arr) {                //遍历list中数据          
        if (str.matches("\\d+") || str.matches("\\d+\\.\\d+")) {    //如果是数字
            stack.push(str);        //入栈
        } else {
            //如果是运算符就弹出两个数据,并做运算,然后再压入栈中
            num1 = Double.parseDouble(stack.pop());
            num2 = Double.parseDouble(stack.pop());
            ret = operation(num1, num2, str) + "";        //返回类型为double,将其转化为String类型,因为是<String>栈
            stack.push(ret);
        }
    }
    //最后栈中剩一个元素,就是结果
    return Double.parseDouble(stack.pop());    //最后一步要记得类型转换
}

 举例:

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值