栈实现简单计算器(二)??中缀表达式转为后缀表达式

1.中缀表达式转变成后缀表达式思路

  1. 首先创建一个符号栈(存放符号),一个集合(用来存储最终的后缀表达式,
  2. 本来是创建一个栈,但是该栈在遍历过程中只负责入栈没有出栈,并且最终的结果是后缀表达式的逆序,所以采用list更方便)
  3. 处理数字:当遍历中缀表达式为数字(用正则表达式匹配)直接添加到集合中
  4. 处理小括号和栈空:当为符号"(“或者栈为空时,直接入符号栈;当为”)",直接遍历符号栈并将
  5. 符号栈的符号添加到集合中,直到符号栈的栈顶为"(",循环结束在出栈栈顶"(";
  6. 处理运算符优先级:当将要入栈的运算符优先级比栈顶的运算符优先级低(小括号不是运算符,只是影响运算顺序),
    出栈栈顶元素并添加到集合中;优先级反之或栈为空,就结束循环,之后元素再入栈
  7. 最后将符号栈的元素全部出栈并添加到集合

2.后缀表达式(逆波兰表达式)计算规则

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,
弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),
并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
(3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 -
从左至右扫描,将3和4压入堆栈;
遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
将5入栈;
接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
将6入栈;
最后是-运算符,计算出35-6的值,即29,由此得出最终结果

3.(重点)将中缀表达式转为集合存储

/**
 * 将中缀表达式转换成集合存储(重点)
 * @author zh
 * @date 2021/7/15 20:47
 * @param expression:  中缀表达式
 * @return java.util.List<java.lang.String>
 **/
    public static List<String> expreConvertList(String expression){
        /*用于存储中缀表达式*/
        List<String> list=new ArrayList<>();
        /*用于处理多位数*/
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < expression.length(); i++) {
            /*获取字符串的每个字符并转换成字符串类型*/
            String  c = ""+expression.charAt(i);
            /*用正则表达式匹配到是数字( c >=48&&c<=57)也可以用ascii表值判断是否是数字),添加到sb中*/
            if (c.matches("^\\d+$")){
                sb.append(c);
                /*当为循环最后一次时是数字,那么就直接将sb的数字添加到集合中*/
                if (i==expression.length()-1){
                    list.add(sb.toString());
                }
            }else {
                /*当有连续的符号时,sb是空的,不能添加,如果不是那代表数字已经结束了,可以将sb存入集合中*/
                if (sb.length()>0){
                    list.add(sb.toString());
                }
                /*直接将字符存入集合中*/
                list.add(c);
                /*用完sb就将sb置为空*/
                sb=new StringBuilder();
            }
        }
        return list;
    }

4.获得运算符优先级

 /**
    * 得到运算符优先级
    * @author zh
    * @date 2021/7/16 8:25
    * @param sign:  运算符
    * @return int
    **/
    public static int  getPriority(int sign){
        if (sign=='*'||sign=='/'){
            return 1;
        }else if (sign == '+' || sign == '-'){
            return 0;
        } else {
            System.out.println("不合法");
            return -1;
        }
    }

5.中缀表达式转为后缀表达式

  /*
    初始化两个栈:运算符栈s1和储存中间结果的栈s2;
    2)从左至右扫描中缀表达式
    3)遇到操作数时,将其压s2;
    4)遇到运算符时,比较其与s1栈顶运算符的优先级:
    1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
    3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
    5)遇到括号时:
    (1)如果是左括号“(”,则直接压入s1
    (2)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
    6)重复步骤2至5,直到表达式的最右边
    7)将s1中剩余的运算符依次弹出并压入s2
    8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
     **/
    /**
     * 中缀转为后缀(重点)
     * @author zh
     * @date 2021/7/16 8:13
     * @param expreList:  中缀表达式的集合形式
     * @return java.util.List<java.lang.String>
     **/
    public static List<String> infixToSuffix(List<String> expreList){
        /*符号栈*/
        Stack<String> fu=new Stack<>();
        /*存储中间结果和最终结果栈,由于在整个操作中该栈并没有出栈菜哦做,
        而且最终结果也是逆序保存,所以该栈没必要可以用list代替*/
        List<String> bi=new ArrayList<>();
        for (String s : expreList) {
            /*如果该值为数字,那么直接添加到集合中*/
            if (s.matches("^\\d+$")){
                bi.add(s);
            /*如果该值为"(",由于运算优先级最大,直接入符号栈*/
            }else if ("(".equals(s)||fu.isEmpty()){
                fu.push(s);
            /*如果该值为")",那就不入栈,将栈中元素出栈并添加到集合中直到栈顶为"(",
              当循环结束后栈顶为"(",直接将"("出栈,这番操作去除了"()"*/
            }else if(")".equals(s)){
                while (!"(".equals(fu.peek())){
                    bi.add( fu.pop());
                }
                /*这时候栈顶是(,直接出栈*/
                fu.pop();
            }else {
                /*当fu栈为空或fu栈栈顶为"("或将要入栈的运算符比栈顶运算符的优先级更高,直接入栈*/
                if ( "(".equals(fu.peek())||getPriority(fu.peek().charAt(0))<getPriority(s.charAt(0))){
                    fu.push(s);
                }else {
                    /*处理入栈的运算符比栈顶运算符的优先级更低或相同
                    * 如果入栈的运算符比栈顶运算符的优先级更低或相同并且栈顶不为"("将栈顶出栈并添加到集合中,
                    * 否则就直接入栈(优先级不满足或则栈顶为"("),循环结束,不然就直接当栈空循环结束
                    **/
                        while (!fu.isEmpty()){
                            if (!"(".equals(fu.peek())&&getPriority(fu.peek().charAt(0))>=getPriority(s.charAt(0))){
                                bi.add(fu.pop());
                            }else {
                                break;
                            }
                        }
                        fu.push(s);
                    }
                }
            }
        /*将符号栈的元素全部添加到集合中*/
        while (!fu.isEmpty()){
            bi.add(fu.pop());
        }
        return bi;
    }

6.测试主方法

 public static void main(String[] args) {
        /*测试*/
      System.out.println(expreConvertList("1+((211+3)*4)-5"));
      /*中缀表达式的集合形式*/
      List<String> infixList = expreConvertList("1+(1+6/2*(211+3)*4+2*4)-5");
      /*转成后缀表达式*/
      List<String> list = infixToSuffix(expreConvertList("1+(1+6/2*(211+3)*4+2*4)-5"));
      /*计算后缀表达式*/
      System.out.println(calculate(list));
  }

7.完整代码

package Stack;

/*
 * @author zh
 * @ClassName : Stack.ReversePolishNotation
 * @Description : 类描述
 * Created by user on 2021-07-15 17:02:54
 * Copyright  2020 user. All rights reserved.
 * 中缀表达式--->逆波兰表达式(后缀表达式,适合计算机计算)--->计算结果
 */

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class ReversePolishNotation {
    /**
     * 方法描述
     * @param: [expression]
     * @return: int
     * @author: zh
     * @date: 2021/7/15
     * 将传过来的后缀表达式计算出结果
    */
    public static int calculate(List<String> list){
        Stack<String> stack=new Stack<>();
        System.out.println(list);
        for (String s : list) {
            /*匹配多位数*/
            if (s.matches("\\d+")){
                stack.push(s);
            }else {
                int num1=Integer.parseInt(stack.pop());
                int num2=Integer.parseInt(stack.pop());
                int res=0;
                switch (s){
                    case("+"):
                        res=num1+num2;break;
                    case("-"):
                        res=num2-num1;break;
                    case("*"):
                        res=num1*num2;break;
                    case("/"):
                        res=num2/num1;break;
                    default:
                        System.out.println("有误");
                }
                stack.push(String.valueOf(res));
            }
        }
        return Integer.parseInt(stack.pop());
    }
/**
 * 将中缀表达式转换成集合存储(重点)
 * @author zh
 * @date 2021/7/15 20:47
 * @param expression:  中缀表达式
 * @return java.util.List<java.lang.String>
 **/
    public static List<String> expreConvertList(String expression){
        /*用于存储中缀表达式*/
        List<String> list=new ArrayList<>();
        /*用于处理多位数*/
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < expression.length(); i++) {
            /*获取字符串的每个字符并转换成字符串类型*/
            String  c = ""+expression.charAt(i);
            /*用正则表达式匹配到是数字( c >=48&&c<=57)也可以用ascii表值判断是否是数字),添加到sb中*/
            if (c.matches("^\\d+$")){
                sb.append(c);
                /*当为循环最后一次时是数字,那么就直接将sb的数字添加到集合中*/
                if (i==expression.length()-1){
                    list.add(sb.toString());
                }
            }else {
                /*当有连续的符号时,sb是空的,不能添加,如果不是那代表数字已经结束了,可以将sb存入集合中*/
                if (sb.length()>0){
                    list.add(sb.toString());
                }
                /*直接将字符存入集合中*/
                list.add(c);
                /*用完sb就将sb置为空*/
                sb=new StringBuilder();
            }
        }
        return list;
    }
   /**
    * 得到运算符优先级
    * @author zh
    * @date 2021/7/16 8:25
    * @param sign:  运算符
    * @return int
    **/
    public static int  getPriority(int sign){
        if (sign=='*'||sign=='/'){
            return 1;
        }else if (sign == '+' || sign == '-'){
            return 0;
        } else {
            System.out.println("不合法");
            return -1;
        }
    }
    /*
    初始化两个栈:运算符栈s1和储存中间结果的栈s2;
    2)从左至右扫描中缀表达式
    3)遇到操作数时,将其压s2;
    4)遇到运算符时,比较其与s1栈顶运算符的优先级:
    1.如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2.否则,若优先级比栈顶运算符的高,也将运算符压入s1;
    3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
    5)遇到括号时:
    (1)如果是左括号“(”,则直接压入s1
    (2)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
    6)重复步骤2至5,直到表达式的最右边
    7)将s1中剩余的运算符依次弹出并压入s2
    8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式
     **/
    /**
     * 中缀转为后缀(重点)
     * @author zh
     * @date 2021/7/16 8:13
     * @param expreList:  中缀表达式的集合形式
     * @return java.util.List<java.lang.String>
     **/
    public static List<String> infixToSuffix(List<String> expreList){
        /*符号栈*/
        Stack<String> fu=new Stack<>();
        /*存储中间结果和最终结果栈,由于在整个操作中该栈并没有出栈菜哦做,
        而且最终结果也是逆序保存,所以该栈没必要可以用list代替*/
        List<String> bi=new ArrayList<>();
        for (String s : expreList) {
            /*如果该值为数字,那么直接添加到集合中*/
            if (s.matches("^\\d+$")){
                bi.add(s);
            /*如果该值为"(",由于运算优先级最大,直接入符号栈*/
            }else if ("(".equals(s)||fu.isEmpty()){
                fu.push(s);
            /*如果该值为")",那就不入栈,将栈中元素出栈并添加到集合中直到栈顶为"(",
              当循环结束后栈顶为"(",直接将"("出栈,这番操作去除了"()"*/
            }else if(")".equals(s)){
                while (!"(".equals(fu.peek())){
                    bi.add( fu.pop());
                }
                /*这时候栈顶是(,直接出栈*/
                fu.pop();
            }else {
                /*当fu栈为空或fu栈栈顶为"("或将要入栈的运算符比栈顶运算符的优先级更高,直接入栈*/
                if ( "(".equals(fu.peek())||getPriority(fu.peek().charAt(0))<getPriority(s.charAt(0))){
                    fu.push(s);
                }else {
                    /*处理入栈的运算符比栈顶运算符的优先级更低或相同
                    * 如果入栈的运算符比栈顶运算符的优先级更低或相同并且栈顶不为"("将栈顶出栈并添加到集合中,
                    * 否则就直接入栈(优先级不满足或则栈顶为"("),循环结束,不然就直接当栈空循环结束
                    **/
                        while (!fu.isEmpty()){
                            if (!"(".equals(fu.peek())&&getPriority(fu.peek().charAt(0))>=getPriority(s.charAt(0))){
                                bi.add(fu.pop());
                            }else {
                                break;
                            }
                        }
                        fu.push(s);
                    }
                }
            }
        /*将符号栈的元素全部添加到集合中*/
        while (!fu.isEmpty()){
            bi.add(fu.pop());
        }
        return bi;
    }
  public static void main(String[] args) {
        /*测试*/
      System.out.println(expreConvertList("1+((211+3)*4)-5"));
      /*中缀表达式的集合形式*/
      List<String> infixList = expreConvertList("1+(1+6/2*(211+3)*4+2*4)-5");
      /*转成后缀表达式*/
      List<String> list = infixToSuffix(expreConvertList("1+(1+6/2*(211+3)*4+2*4)-5"));
      /*计算后缀表达式*/
      System.out.println(calculate(list));
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值