中缀表达式转换为后缀表达式实现基本计算机功能

这篇博客详细介绍了如何将中缀表达式转换为后缀表达式,以及如何利用后缀表达式实现一个简单的计算器。通过扫描中缀表达式,使用两个栈分别处理运算符和中间结果,遵循运算符优先级规则,最终得到后缀表达式。此外,还展示了后缀表达式计算器的实现,从左到右扫描后缀表达式,逐个处理数字和运算符,完成计算过程。
摘要由CSDN通过智能技术生成

前缀、中缀、后缀表达式(逆波兰表达式)举例说明
运算表达式:(3+4)*5-6
前缀表达式:- * + 3 4 5 6(从右向左扫描)
中缀表达式:(3+4)*5-6 (我们人常见的运算表达式)
后缀表达式:3 4 + 5 * 6 -(从左向右扫描,与前缀表达式相反)

中缀表达式转为后缀表达式的思路
1)初始化两个栈:运算符栈s1和储存中间结果的栈s2
2)从左到右扫描中缀表达式
3)遇到数字时,将其压入s2
4)遇到运算符时,比较其与s1栈顶运算符的优先级
1.如果s1为空,或栈顶运算符为“(”,则直接将此运算符入栈
2.若此运算符优先级比栈顶运算符高,也将运算符压入s1
3.否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4)中与s1中新的栈顶的运算符比较
5)遇到括号时,
1.如果是左括号“(”,则直接压入s1
2.如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止
3.将这一对括号舍弃
6)重复步骤2至5,知道表达式的最右边
7)将s1中剩余的运算符依次弹出并压入s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

代码实现

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

public class PolandNotation {
    //将中缀表达式转成对应的list集合
    public static List<String> toList(String expression){
        //创建一个list,存放中缀表达式 对应的内容
        List<String> list=new ArrayList<>();
        int i=0;//相当于一个指针,用于遍历中缀表达式字符串
        String str;//对多位数进行拼接
        char c;//每遍历到一个字符,就放入到c中
        do{
            //根据ASCIL码,数字在[48,57]之间
            //如果c是个非数字,则添加到list中
            if((c=expression.charAt(i))<48||(c=expression.charAt(i))>57){
                list.add(c+"");
                i++;//i往后移
            }else{
                //如果是位多位数,需要考虑字符串拼接
                str="";//重置
                //需要考虑是否为最后一个数字
                //防止越界问题
                while(i<expression.length()&&(c=expression.charAt(i))>=48&&(c=expression.charAt(i))<=57){
                    str+=c;
                    i++;
                }
                list.add(str);
            }
        }while(i<expression.length());
        return list;//返回list集合
    }
    //将中缀表达式对应的list转换为后缀表达式对应的list
    public static List<String> transformList(List<String> list) {
        //定义两个栈
        Stack<String> s1 = new Stack<>();//符号栈
        //由于s2这个栈,在整个过程中,没有弹栈(pop)操作,而且最后还要逆序输出
        //比较麻烦,因此这里不使用栈Stack,而使用集合List<String> s2
        List<String> s2 = new Stack<>();//储存中间结果

        //遍历 list
        for (String element : list) {
            //如果是一个数,则添加到s2中
            //运用正则表达式
            if (element.matches("\\d+")) {
                s2.add(element);
            } else if (element.equals("(")) {
                s1.push(element);
            } else if (element.equals(")")) {
                //依次弹出s1栈顶的运算符,并压入s2中,直到遇到左括号为止
                //peek()方法  查看栈顶的元素
                while (!(s1.peek().equals("("))) {
                    s2.add(s1.pop());
                }
                s1.pop();//把左括号“(”弹出
            } else {
                //当element运算符的优先级<=s1栈顶运算符,将s1栈顶的运算符弹出并添加到s2中
                //然后再与s1中新的栈顶运算符比较
                while(s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(element)){
                    s2.add(s1.pop());
                }
                //之后将element压入栈
                s1.push(element);
            }
        }

        //将s1中剩余的运算符依次弹出并添加到s2中
        while(s1.size()!=0){
            s2.add(s1.pop());
        }
        //由于存放在list集合中,因此按顺序输出就是对应的后缀表达式
        return s2;
    }

}
    //编写一个类,可以返回一个运算符对应的优先级
    class Operation{
        private static int ADD=1;
        private static int SUB=1;
        private static int MUL=2;
        private static int DIV=2;

        //返回对应的优先级数字
        public static int getValue(String operation){
            int result=0;
            switch(operation){
                case"+":
                    result=ADD;
                    break;
                case"-":
                    result=SUB;
                    break;
                case"*":
                    result=MUL;
                    break;
                case"/":
                    result=DIV;
                    break;
                case"(":
                    result=0;
                    break;
                default:
                    System.out.println("不存在该运算符");
                    break;
            }
            return result;
    }
}

后缀表达式实现计算器
思路分析
例如:2*(3+4)5-6 对应的后缀表达式为 2 3 4 + * 5 * 6 -;后缀表达式求值步骤如下:
1)从左到右扫描,将2、3以及4压入栈中
2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7压入栈
3)遇到 * 运算符,因此弹出7和2,计算出2
7的值,得14,再将14压入栈
4)将5压入栈
5)遇到 * 运算符,因此弹出5和14,计算出14*5=70,将70压入栈
6)将6压入栈
7)最后是-运算符,计算出70-6=64,则64为最终结果
注意
减法和除法一定要仔细点,要知道次顶元素为被减数(被除数),栈顶元素为减数(除数)

代码实现

   //实现对后缀表达式(逆波兰表达式)的运算
    public static int calculate(List<String> list){
        //创建一个栈
        Stack<String> stack=new Stack<>();
        //遍历list
        for(String element:list){
            //使用正则表达式,匹配的是多位数,一位数也行
            //如果是数就入栈
            if(element.matches("\\d+")){
                stack.push(element);
            }else{
                //否则弹(pop)出两个数,进行运算
                int num2=Integer.parseInt(stack.pop());
                int num1=Integer.parseInt(stack.pop());
                int result=0;
                if(element.equals("+")){
                    result=num1+num2;
                }else if(element.equals("-")){
                    result=num1-num2;
                }else if(element.equals("*")){
                    result=num1*num2;
                }else if(element.equals("/")){
                    result=num1/num2;
                }else{
                    throw new RuntimeException("运算符有误");
                }
                //把result压入栈
                stack.push(result+"");
            }
        }
        //最后在stack中的数据就是运算结果
        return Integer.parseInt(stack.pop());
    }
}

测试代码

 //测试
    public static void main(String[] args) {
        //String s="2*(3+4)*5-6";
        String s="3*(4*5/4+(5-4))/5";
        List<String> list=toList(s);
        List<String> li=transformList(list);
        //System.out.println(calculate(li));//64
        System.out.println(calculate(li));//3
    }

中缀表达式转为后缀表达式及实现基本计算器代码如下

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

public class PolandNotation {
    //将中缀表达式转成对应的list集合
    public static List<String> toList(String expression){
        //创建一个list,存放中缀表达式 对应的内容
        List<String> list=new ArrayList<>();
        int i=0;//相当于一个指针,用于遍历中缀表达式字符串
        String str;//对多位数进行拼接
        char c;//每遍历到一个字符,就放入到c中
        do{
            //根据ASCIL码,数字在[48,57]之间
            //如果c是个非数字,则添加到list中
            if((c=expression.charAt(i))<48||(c=expression.charAt(i))>57){
                list.add(c+"");
                i++;//i往后移
            }else{
                //如果是位多位数,需要考虑字符串拼接
                str="";//重置
                //需要考虑是否为最后一个数字
                //防止越界问题
                while(i<expression.length()&&(c=expression.charAt(i))>=48&&(c=expression.charAt(i))<=57){
                    str+=c;
                    i++;
                }
                list.add(str);
            }
        }while(i<expression.length());
        return list;//返回list集合
    }
    //将中缀表达式对应的list转换为后缀表达式对应的list
    public static List<String> transformList(List<String> list) {
        //定义两个栈
        Stack<String> s1 = new Stack<>();//符号栈
        //由于s2这个栈,在整个过程中,没有弹栈(pop)操作,而且最后还要逆序输出
        //比较麻烦,因此这里不使用栈Stack,而使用集合List<String> s2
        List<String> s2 = new Stack<>();//储存中间结果

        //遍历 list
        for (String element : list) {
            //如果是一个数,则添加到s2中
            //运用正则表达式
            if (element.matches("\\d+")) {
                s2.add(element);
            } else if (element.equals("(")) {
                s1.push(element);
            } else if (element.equals(")")) {
                //依次弹出s1栈顶的运算符,并压入s2中,直到遇到左括号为止
                //peek()方法  查看栈顶的元素
                while (!(s1.peek().equals("("))) {
                    s2.add(s1.pop());
                }
                s1.pop();//把左括号“(”弹出
            } else {
                //当element运算符的优先级<=s1栈顶运算符,将s1栈顶的运算符弹出并添加到s2中
                //然后再与s1中新的栈顶运算符比较
                while(s1.size()!=0&&Operation.getValue(s1.peek())>=Operation.getValue(element)){
                    s2.add(s1.pop());
                }
                //之后将element压入栈
                s1.push(element);
            }
        }

        //将s1中剩余的运算符依次弹出并添加到s2中
        while(s1.size()!=0){
            s2.add(s1.pop());
        }
        //由于存放在list集合中,因此按顺序输出就是对应的后缀表达式
        return s2;
    }


    //实现对后缀表达式(逆波兰表达式)的运算
    public static int calculate(List<String> list){
        //创建一个栈
        Stack<String> stack=new Stack<>();
        //遍历list
        for(String element:list){
            //使用正则表达式,匹配的是多位数,一位数也行
            //如果是数就入栈
            if(element.matches("\\d+")){
                stack.push(element);
            }else{
                //否则弹(pop)出两个数,进行运算
                int num2=Integer.parseInt(stack.pop());
                int num1=Integer.parseInt(stack.pop());
                int result=0;
                if(element.equals("+")){
                    result=num1+num2;
                }else if(element.equals("-")){
                    result=num1-num2;
                }else if(element.equals("*")){
                    result=num1*num2;
                }else if(element.equals("/")){
                    result=num1/num2;
                }else{
                    throw new RuntimeException("运算符有误");
                }
                //把result压入栈
                stack.push(result+"");
            }
        }
        //最后在stack中的数据就是运算结果
        return Integer.parseInt(stack.pop());
    }
}
    //编写一个类,可以返回一个运算符对应的优先级
    class Operation{
        private static int ADD=1;
        private static int SUB=1;
        private static int MUL=2;
        private static int DIV=2;

        //返回对应的优先级数字
        public static int getValue(String operation){
            int result=0;
            switch(operation){
                case"+":
                    result=ADD;
                    break;
                case"-":
                    result=SUB;
                    break;
                case"*":
                    result=MUL;
                    break;
                case"/":
                    result=DIV;
                    break;
                case"(":
                    result=0;
                    break;
                default:
                    System.out.println("不存在该运算符");
                    break;
            }
            return result;
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值