逆波兰计算器

逆波兰计算器的实现思路

  • 定义:逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasiewicz)于1929年首先提出的一种表达式的表示方法 [1] 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。

      >>整体思路:
      1. 首先我们输入中缀表达式;                              例如:1+((2+3)*4)-5
      2. 将其转换为list集合下的单个元素;                       例如:[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
      3. 再将该list集合转换为后缀表达式的list集合(逆波兰表达式);例如:[1, 2, 3, +, 4, *, +, 5, -]
      4. 再对后缀表达式进行运算;                             得到结果:16
    
  • 页内目录
    一,中缀表达式转换list集合
    二,中缀表达式的list集合转后缀表达式的list集合
    三,对后缀表达式进行计算
    四,测试

思路的实现

一,中缀表达式转换list集合
  >>思路:
  1. 定义存放中缀表达式的list集合
  2. 通过while循环实现逐个添加:
                   3. 情况一:是符号:运用方法charAt判断;并加入list集合
                   4. 情况二:是数字:考虑多位数的情况,并加入到list集合
  5. 返回list集合
    public static List<String> toInfixExpList(String s) {
        //定义一个存放的集合,存放中缀表达式的各项
        List<String> ls = new ArrayList<>();
        int i = 0;//类似指针,用于辅助遍历中缀表达式
        String str;//用于拼接多位数
        do {
            //如果是非数字,加入到ls中
            if (s.charAt(i) < 48 || s.charAt(i) > 57) {
                ls.add("" + s.charAt(i));//将该字符拼成String
                i++;//i需要后移
            } else {//是数
                str = "";//将str置成""
                while (i < s.length() && s.charAt(i) >= 48 && s.charAt(i) <= 57) {//判断该位是否为数字
                    str += s.charAt(i);//保证多位数的拼接
                    i++;//多位数的保证
                }
                ls.add(str);
            }
        } while (i < s.length());
        return ls;
    }
二,中缀表达式的list集合转后缀表达式的list集合
    中缀list:[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
    后缀list:[1, 2, 3, +, 4, *, +, 5, -]   
  >>思路:
  1. 定义符号栈                      
  2. 定义存放后缀表达式的集合           
  3. for循环遍历中缀表达式:
               如果是一个数:则直接存放到集合(用正则表达式判断)
               如果是左括号:则入符号栈
               如果是右括号:运用while循环直到遇见左括号为止(判断是否遇见此处用栈的peek方法);
                            进行依次弹出栈顶的运算符,并存入集合,最后丢弃该括号
               如果是运算符:此处在外写一个判断优先级的方法priority
                            当遍历的元素的优先级小于等于栈顶运算符优先级时,将栈的栈顶元素弹出并加入到集合
                            然后将遍历的元素加入到栈中
  4. 此时将栈中的元素添加到集合中
  5. 返回集合
    public static List<String> toSuffixExpList(List<String> s) {
        //分别定义符号栈和后缀表达式的各项的list集合
        Stack<String> s1 = new Stack<>();//符号栈
        List<String> s2 = new ArrayList<>();
        //遍历s
        for (String item : s) {
            //如果是个数则加入s2,运用正则表达式判断
            if (item.matches("\\d+")) {
                s2.add(item);
            } else if (item.equals("(")) {//如果是左括号
                s1.push(item);//就加入到栈s1中
            } else if (item.equals(")")) {//如果是右括号,则依次弹出栈顶的运算符,并加入s2,直到遇到左括号为止,并丢弃该对括号
                while (!s1.peek().equals("(")) {//通过查看栈顶元素,判断是否到达)
                    s2.add(s1.pop());//将栈s1的栈顶元素弹出,并加入到栈s2
                }
                s1.pop();//弹出(
            } else {//当item的优先级小于等于S1栈顶运算符优先级,将将s1中的栈顶元素弹出并加入到s2
                //在本类中写一个比较优先级的方法priority
                while (s1.size() != 0 && priority(s1.peek()) >= priority(item)) {//栈顶元素比item的优先级高
                    s2.add(s1.pop());
                }
                s1.add(item);//将item压入s1栈
            }
        }
        //将s1的剩余元素加入s2
        while (s1.size() != 0) {
            s2.add(s1.pop());
        }
        return s2;
    }
/**
*priority方法配合使用toSuffixExpList方法
*/
        public static int priority(String item) {
        int result = 0;
        switch (item) {
            case "+":
                result = 1;
                break;
            case "-":
                result = 1;
                break;
            case "*":
                result = 2;
                break;
            case "/":
                result = 2;
                break;
            default:
                System.out.println("该运算符没有录入");
                break;
        }
        return result;
    }
三,对后缀表达式进行计算
    后缀list:[1, 2, 3, +, 4, *, +, 5, -]   
  >>思路:(整个过程注意入栈转String,出栈要运算的数转Integer)
  1. 创建一个栈用于存放计算中的结果
  2. 遍历后缀表达式的元素:
                     如果是数字:存入栈中
                     如果是运算符:pop出栈的两个数根据该运算符进行不同的运算(注意弹出两个数的先后)
                                  将计算结果入栈
  3. 最后栈中元素便是计算结果
    public static int calculate(List<String> ls) {
        //创建一个栈
        Stack<String> stack = new Stack<>();
        //遍历ls
        for (String item : ls) {
            if (item.matches("\\d+")) {
                stack.push(item);
            } else {
                //pop出两个数进行运算,并入栈
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int result = 0;
                if (item.equals("+")) {
                    result = num1 + num2;
                } else if (item.equals("-")) {
                    result = num1 - num2;
                } else if (item.equals("*")) {
                    result = num1 * num2;
                } else if (item.equals("/")) {
                    result = num1 / num2;
                } else {
                    System.out.println("运算符未录入");
                }
                stack.push(result + "");//将计算结果变成String再加入栈中
            }
        }
        //留下来的数据就是结果
        return Integer.parseInt(stack.pop());//取出字符串类型的数字,转成数字类型
    }
四,测试:
    public static void main(String[] args) {
        String infixExp = "1+((2+3)*4)-5";
        //将中缀运算式==>>中缀表达式list集合
        System.out.println(toInfixExpList(infixExp));//[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
        //将中缀表达式的list集合==>>后缀表达式的list集合
        System.out.println(toSuffixExpList(toInfixExpList(infixExp)));//[1, 2, 3, +, 4, *, +, 5, -]
        //对后缀表达式进行计算,即逆波兰表达式的运算
        System.out.println(calculate(toSuffixExpList(toInfixExpList(infixExp))));//16
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值