数据结构之中缀前缀后缀表达式、中缀转后缀、后缀表达式计算器、完整版逆波兰表达式

一、前缀中缀后缀表达式及计算器思路
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二、逆波兰计算器(后缀表达式实现)
用系统的栈,支持小括号

package com.ws..栈计算器后缀;

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

public class PolandNotation {
    public static void main(String[] args) {
        //定义一个逆波兰表达式
        //(3+4)x5-6 => 3 4 + 5 x 6 - =>29
        //用空格隔开
        String string="3 4 + 5 * 6 -";
        //1.将字符串放到ArrayList中
        //2.将ArrayList传递给方法,配合栈完成计算

        List<String> list=getListString(string);//[3, 4, +, 5, *, 6, -]
        System.out.println("要计算的后缀表达式是="+list);

        //计算结果
        int jeiguo=suan(list);
        System.out.println("计算结果是="+jeiguo);

    }

    //将逆波兰表达式,依次将数据和运算符放入到ArrayList中
    public static List<String> getListString(String string){
        //将字符串分割
        String[] listString=string.split(" ");//按照空格分割字符串
        List<String> list=new ArrayList<>();
        for (String s : listString) {//将分割后的字符串放到ArrayList中
            list.add(s);
        }
        return list;
    }
    //从左到右扫描,压入栈
    //遇到运算符,就弹出数字栈两个数进行运算,结果入数栈
    //数栈最后一个元素就是结果
    public static int suan(List<String> ls){
        //创建数栈
        Stack<String> stack = new Stack<>();
        //遍历字符串
        for (String l : ls) {
            //判断取出来的是否是数
            if (l.matches("\\d+")){//匹配的是多位数
                //是数就入栈
                stack.add(l);
            }else {
                //不是数就出栈两个数进行运算,结果入栈
                int shu1=Integer.parseInt(stack.pop());
                int shu2=Integer.parseInt(stack.pop());
                int jieguo=0;
                //判断当前运算符是什么,并计算
                if (l.equals("+")){
                    jieguo=shu2+shu1;
                }else if (l.equals("-")){
                    jieguo=shu2-shu1;
                }else if (l.equals("*")){
                    jieguo=shu2*shu1;
                }else if (l.equals("/")){
                    jieguo=shu2/shu1;
                }else {
                    throw new RuntimeException("运算符有误");
                }
                //结果入数栈
                stack.add(jieguo+"");//整数转字符串
            }
        }
        //最后留在数栈中的就是结果
        return Integer.parseInt(stack.pop());
    }
}

三、中缀转后缀表达式思路)
在这里插入图片描述
过程:
在这里插入图片描述
代码:

package com.ws..栈计算器后缀;

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

public class PolandNotation {
    public static void main(String[] args) {
        //将中缀表达式转换成后缀表达式
        //1+((2+3)x4)-5  转成  1 2 3 + 4 * + 5 -
        String zhongString="1+((2+3)*4)-5";
        List<String> list1 = printfStringList(zhongString);
        System.out.println("中缀表达式转换成字符串之后是="+list1);
        //中缀表达式转换成后缀表达式
        List<String> printfHouList = printfHouList(list1);
        System.out.println("中缀表达式转换成后缀表达式后是="+printfHouList);
        //计算
        System.out.println("转换后计算后缀表达式的结果是="+suan(printfHouList));

        //定义一个逆波兰表达式
        //(3+4)x5-6 => 3 4 + 5 x 6 - =>29
        //用空格隔开
//        String string="3 4 + 5 * 6 -";
//        //1.将字符串放到ArrayList中
//        //2.将ArrayList传递给方法,配合栈完成计算
//
//        List<String> list=getListString(string);//[3, 4, +, 5, *, 6, -]
//        System.out.println("要计算的后缀表达式是="+list);
//
//        //计算结果
//        int jeiguo=suan(list);
//        System.out.println("计算结果是="+jeiguo);

    }

    //将中缀表达式转换成对应的字符串
    public static List<String> printfStringList(String s){
        //定义一个List存放中缀表达式的数据
        List<String> ls=new ArrayList<>();
        int i=0;//用于遍历中缀表达式字符串
        String str;//对多位数拼接
        char c;//遍历每一个字符
        do{
            //如果是非数字就加入ls里
            if ((c=s.charAt(i))<48||(c=s.charAt(i))>57){
                ls.add(""+c);//加入
                i++;//后移
            }else {//如果是数字,就要考虑多位数问题
                str="";//将str置空       0到9
                while (i<s.length()&&(c=s.charAt(i))>=48&&(c=s.charAt(i))<=57){
                    str+=c;//拼接
                    i++;
                }
                ls.add(str);//加入
            }
        }while (i<s.length());//小于字符串长度就继续遍历
        return ls;
    }

    //将中缀表达式转换成后缀表达式
    //[1, +, (, (, 2, +, 3, ), x, 4, ), -, 5]=>[1, 2, 3, +, 4, *, 5, -]
    public static List<String> printfHouList(List<String> ls){
        //定义两个栈
        Stack<String> s1=new Stack<>();//符号栈,用于暂时存放括号和符号
        //存储中间的栈,一直没有出栈,一直在入栈,结果就是他,所以用List就行
        List<String> s2=new ArrayList<>();//中间结果
        //遍历ls
        for (String item : ls) {
            //如果是一个数就加入中间结果栈
            if (item.matches("\\d+")) {
                s2.add(item);
            }
            //如果是(就加入符号栈
            else if (item.equals("(")){
                s1.push(item);
            }
            //如果是)就依次弹出符号栈加入中间结果栈,直到遇到(为止,并将这一对括号去掉
            else if (item.equals(")")){
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//将(弹出,去掉
            }else {
                //当当前符号优先级小于等于符号栈栈顶优先级就弹出符号栈运算符栈顶,并压入到中间结果中,之后继续与符号栈比较优先级
                while (s1.size()!=0&&printfYouxian.getYouxian(s1.peek())>=printfYouxian.getYouxian(item)){
                    s2.add(s1.pop());
                }
                //将当前运算符加入符号栈
                s1.push(item);
            }
        }
        //将运算符栈加入到中间状态中
        while (s1.size()!=0){
            s2.add(s1.pop());
        }
        return s2;
    }




    //将逆波兰表达式,依次将数据和运算符放入到ArrayList中
    public static List<String> getListString(String string){
        //将字符串分割
        String[] listString=string.split(" ");//按照空格分割字符串
        List<String> list=new ArrayList<>();
        for (String s : listString) {//将分割后的字符串放到ArrayList中
            list.add(s);
        }
        return list;
    }




    //从左到右扫描,压入栈
    //遇到运算符,就弹出数字栈两个数进行运算,结果入数栈
    //数栈最后一个元素就是结果
    public static int suan(List<String> ls){
        //创建数栈
        Stack<String> stack = new Stack<>();
        //遍历字符串
        for (String l : ls) {
            //判断取出来的是否是数
            if (l.matches("\\d+")){//匹配的是多位数
                //是数就入栈
                stack.add(l);
            }else {
                //不是数就出栈两个数进行运算,结果入栈
                int shu1=Integer.parseInt(stack.pop());
                int shu2=Integer.parseInt(stack.pop());
                int jieguo=0;
                //判断当前运算符是什么,并计算
                if (l.equals("+")){
                    jieguo=shu2+shu1;
                }else if (l.equals("-")){
                    jieguo=shu2-shu1;
                }else if (l.equals("*")){
                    jieguo=shu2*shu1;
                }else if (l.equals("/")){
                    jieguo=shu2/shu1;
                }else {
                    throw new RuntimeException("运算符有误");
                }
                //结果入数栈
                stack.add(jieguo+"");//整数转字符串
            }
        }
        //最后留在数栈中的就是结果
        return Integer.parseInt(stack.pop());
    }
}

//返回优先级类
class printfYouxian{
    private static int ADD=1;//加法
    private static int SUB=1;//减法
    private static int MUL=2;//乘法
    private static int DIV=2;//除法

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

四、完整版逆波兰表达式
在这里插入图片描述
代码:

package com.ws..完整逆波兰计算器;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
public class ReversePolishMultiCalc {
    /**
     * 匹配 + - * / ( ) 运算符
     */
    static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)";
    static final String LEFT = "(";
    static final String RIGHT = ")";
    static final String ADD = "+";
    static final String MINUS= "-";
    static final String TIMES = "*";
    static final String DIVISION = "/";
    /**
     * 加減 + - */
    static final int LEVEL_01 = 1;
    
    /**
     * 乘除 * /
     */
    static final int LEVEL_02 = 2;
    /**
     * 括号
     */
    static final int LEVEL_HIGH = Integer.MAX_VALUE;
    static Stack<String> stack = new Stack<>();
    static List<String> data = Collections.synchronizedList(new ArrayList<String>());
    /**
     * 去除所有空白符
     * @param s
     * @return
     */
    public static String replaceAllBlank(String s ){
// \\s+ 匹配任何空白字符,包括空格、制表符、换页符等等, 等价于[ \f\n\r\t\v]
        return s.replaceAll("\\s+","");
    }
    /**
     * 判断是不是数字 int double long float
     尚硅谷 Java 数据结构和算法
     更多 Java –大数据 –前端 –python 人工智能 -区块链资料下载,可访问百度:尚硅谷官网 第 94页
     * @param s
     * @return
     */
    public static boolean isNumber(String s){
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(s).matches();
    }
    /**
     * 判断是不是运算符
     * @param s
     * @return
     */
    public static boolean isSymbol(String s){
        return s.matches(SYMBOL);
    }
    /**
     * 匹配运算等级
     * @param s
     * @return
     */
    public static int calcLevel(String s){
        if("+".equals(s) || "-".equals(s)){
            return LEVEL_01;
        } else if("*".equals(s) || "/".equals(s)){
            return LEVEL_02;
        }
        return LEVEL_HIGH;
    }
    /**
     * 匹配
     * @param s
     * @throws Exception
     */
    public static List<String> doMatch (String s) throws Exception{
        if(s == null || "".equals(s.trim())) throw new RuntimeException("data is empty");
        if(!isNumber(s.charAt(0)+"")) throw new RuntimeException("data illeagle,start not with a number");
        s = replaceAllBlank(s);
        String each;
        int start = 0;
        for (int i = 0; i < s.length(); i++) {
            if(isSymbol(s.charAt(i)+"")){
                each = s.charAt(i)+"";
//栈为空,(操作符,或者 操作符优先级大于栈顶优先级 && 操作符优先级不是( )的优先级 及

                if(stack.isEmpty() || LEFT.equals(each)
                        || ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)){

                    stack.push(each);
                }else if( !stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())){
//栈非空,操作符优先级小于等于栈顶优先级时出栈入列,直到栈为空,或者遇到了(,最后

                    while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek()) ){
                        if(calcLevel(stack.peek()) == LEVEL_HIGH){
                            break;
                        }
                        data.add(stack.pop());
                    }
                    stack.push(each);
                }else if(RIGHT.equals(each)){
// ) 操作符,依次出栈入列直到空栈或者遇到了第一个)操作符,此时)出栈
                    while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())){
                        if(LEVEL_HIGH == calcLevel(stack.peek())){
                            stack.pop();
                            break;
                        }
                        data.add(stack.pop());
                    }
                }
                start = i ; //前一个运算符的位置
            }else if( i == s.length()-1 || isSymbol(s.charAt(i+1)+"") ){
                each = start == 0 ? s.substring(start,i+1) : s.substring(start+1,i+1);
                if(isNumber(each)) {
                    data.add(each);
                    continue;
                }
                throw new RuntimeException("data not match number");
            }
        }
//如果栈里还有元素,此时元素需要依次出栈入列,可以想象栈里剩下栈顶为/,栈底为+,应该依次出栈

        Collections.reverse(stack);
        data.addAll(new ArrayList<>(stack));
        System.out.println(data);
        return data;
    }
    /**
     * 算出结果
     * @param list
     * @return
     */
    public static Double doCalc(List<String> list){
        Double d = 0d;
        if(list == null || list.isEmpty()){
            return null;
        }
        if (list.size() == 1){
            System.out.println(list);

            d = Double.valueOf(list.get(0));
            return d;
        }
        ArrayList<String> list1 = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            list1.add(list.get(i));
            if(isSymbol(list.get(i))){
                Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));
                list1.remove(i);
                list1.remove(i-1);
                list1.set(i-2,d1+"");
                list1.addAll(list.subList(i+1,list.size()));
                break;
            }
        }
        doCalc(list1);
        return d;
    }
    /**
     * 运算
     * @param s1
     * @param s2
     * @param symbol
     * @return
     */

    public static Double doTheMath(String s1,String s2,String symbol){
        Double result ;
        switch (symbol){
            case ADD : result = Double.valueOf(s1) + Double.valueOf(s2); break;
            case MINUS : result = Double.valueOf(s1) - Double.valueOf(s2); break;
            case TIMES : result = Double.valueOf(s1) * Double.valueOf(s2); break;
            case DIVISION : result = Double.valueOf(s1) / Double.valueOf(s2); break;
            default : result = null;
        }
        return result;
    }
    public static void main(String[] args) {
//String math = "9+(3-1)*3+10/2";
        String math = "12.8 + (2 - 3.55)*4+10/5.0";
        try {
            doCalc(doMatch(math));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值