一、什么前缀、中缀、后缀表达式(使用 8*(5+6)-1的例子)

1.中缀表达式:8*(5+6)-1;(也就是我们平常所见的运算式)
2.后缀表达式:8 5 6 + * 1 - ;计算机是怎么运算的呢?
从左向右进行遍历,数字放到数据栈中,也就是8 5 6;当遍历到+号时,从数据栈中弹出两个距离+号最近的数据进行相加,也就是5 和 6,得到结果13入栈中;接着遍历,当遇到 *号时,从栈中弹出距离 *最近的两个数据进行相乘,也就是13和8,将结果104入栈中;遍历到1入数据栈,接着遍历到-号,同样从数据栈中取出距离-号最近的两个数据进行相减,也就是104和1,最后的结果103入栈中,遍历结束
3.前缀表达式:- 1 *+ 6 5 8(类似与后缀表达式,只不过是从右向左进行遍历)

这三个表达式的结果都是相同的,只不过计算机更倾向于后缀表达式(波兰表达式)

二、中缀表达式转前缀表达式

1.思路:

*1.如果使用两个栈进行操作,发现数据栈没有出栈的操作,所以可以使用List代替数据栈
* 2.遍历表达式
* 3.如果是数字,则入加入集合
* 4.如果是运算符,需要考虑以下这几种情况
* 情况一:运算符栈如果为空,则将运算符直接入栈;
* 情况二:如果栈顶为"(",则直接将运算符入栈
* 情况三:如果该运算符大于栈顶的运算符,则直接将该运算符入栈
* 否则,将栈顶运算符添加到集合中,继续重复这几种情况,直到该运算符入栈
* 5.如果遇到“)”,判断栈顶的符号是否是“(”,如果不是,则将栈顶运算符加入到集合中;如果是,则将这两个括号丢弃
* 6.遍历表达式结束,就将剩余栈中的数据加入到集合中
* 7.将list反转,形成前缀表达式

2.代码

package com.company;

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

/**
 * @author:抱着鱼睡觉的喵喵
 * @date:2021/2/20
 * @description:
 */
public class InfixToPrefix {

    public static void main(String[] args) {
        String str = "8*((6-4)+1)";
        List<String> strList = toInfixStrList(str);
        for (String temp : strList) {
            System.out.printf(temp);
        }
        System.out.println();
        List<String> list = toInfixTransformPrefix(strList);
        for (String temp : list) {
            System.out.printf(temp);
        }
        int result = cal(list);
        System.out.printf("结果为:%d",result);
    }

    /**
     * 将表达式存入list集合中
     * @param str
     * @return
     */
    public static List<String> toInfixStrList(String str) {
        char ch;
        int i = 0;
        String cs = "";
        List<String> list = new ArrayList<>();
        do {
            if ((ch = str.charAt(i)) < 48 || (ch = str.charAt(i)) > 57) {   //数字的区间[48,56]
                list.add("" + ch);
                i++;
            } else {        //这里是为了考虑多位数的情况
                while (i < str.length() && (ch = str.charAt(i)) >= 48 && (ch = str.charAt(i)) <= 57) {
                    cs += ch;   //字符的拼接  "5" + "6" = "56";
                    i++;
                }
                list.add(cs);
                cs = "";
            }
        } while (i < str.length());
        return list;
    }

    /**
     * 中缀转前缀思路:
     * 1.如果使用两个栈进行操作,发现数据栈没有出栈的操作,所以可以使用List代替数据栈
     * 2.遍历表达式
     * 3.如果是数字,则入加入集合
     * 4.如果是运算符,需要考虑以下这几种情况
     *  情况一:运算符栈如果为空,则将运算符直接入栈;
     *  情况二:如果栈顶为"(",则直接将运算符入栈
     *  情况三:如果该运算符大于栈顶的运算符,则直接将该运算符入栈
     *  否则,将栈顶运算符添加到集合中,继续重复这几种情况,直到该运算符入栈
     * 5.如果遇到“)”,判断栈顶的符号是否是“(”,如果不是,则将栈顶运算符加入到集合中;如果是,则将这两个括号丢弃
     * 6.遍历表达式结束,就将剩余栈中的数据加入到集合中
     * 7.将list反转,形成前缀表达式
     * @param list
     * @return
     */
    public static List<String> toInfixTransformPrefix(List<String> list) {
        Stack<String> opStack = new Stack<>();
        List<String> numList = new ArrayList<>();
        String temp = "";
        for (int i = 0; i < list.size(); i++) {     //遍历
            temp = list.get(i);                     //使用临时遍历temp记录每一次遍历的数据
            if (temp.matches("\\d+")) {         //使用正则表达式(/d+),是否是数字
                numList.add(temp);                      //如果是则加入集合中
            } else if (temp.equals(")")) {              //判断是否是“)”,如果是要循环将栈顶的运算符加入到集合中,直到遇到“(”,并将两个括号丢弃
                while (!opStack.peek().equals("(")) {
                    numList.add(opStack.pop());
                }
                opStack.pop();  //丢弃括号
                continue;
            } else if (Operation.isOperation(temp)) {   //如果是运算符,考虑三种情况
                while (!opStack.isEmpty() && !opStack.peek().equals("(") && (Operation.priority(temp) <= Operation.priority(opStack.peek()))) {
                    numList.add(opStack.pop());
                }
                opStack.push(temp);         //将运算符入栈
            }else if (temp.equals("(")) {       //如果是左括号直接入栈
                opStack.push(temp);
            } else {
                throw new RuntimeException("你输入的表达式有误!");
            }
        }
        while (!opStack.isEmpty()) {        //遍历结束,将栈中剩余数据加入到集合中
            numList.add(opStack.pop());
        }
        Collections.reverse(numList);       //list反转
        return numList;
    }
    public static int cal(List<String> list) {
        Stack<String> stack = new Stack<>();
        int num1 = 0;
        int num2 = 0;
        int result;
        String ele="";
        for (int i = list.size() - 1;i >= 0; i--) {
            ele = list.get(i);
            if (ele.matches("\\d+")) {      //匹配的是一位数或者多位数(\d+)
                stack.push(ele);
            } else {
                result = 0;
                num1 = Integer.parseInt(stack.pop());
                num2 = Integer.parseInt(stack.pop());
                if (ele.equals("+")) {
                    result = num2 + num1;
                } else if (ele.equals("-")) {
                    result = num2 - num1;
                } else if (ele.equals("*")) {
                    result = num2 * num1;
                } else if (ele.equals("/")) {
                    result = num2 / num1;
                } else {
                    throw new RuntimeException("运算符有误!");
                }
                stack.push(""+result);
            }
        }
        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 DEL = 2;

    public static boolean isOperation(String s) {
        return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/");
    }

    /**
     * 使用1 2 表示运算符的优先级
     * @param s
     * @return
     */
    public static int priority(String s) {
        switch (s) {
            case "+":
                return ADD;
            case "-":
                return SUB;
            case "*":
                return MUL;
            case "/":
                return DEL;
            default:
                throw new RuntimeException("符号有误!");
        }
    }
}

三、中缀表达式转前缀表达式

1.思路:

* 1.定义两个栈,数据栈numStack和运算符栈opStack
 * 2.从左到右遍历中缀表达式
 * 3.如果是数字则压入numStack数据栈中
 * 4.如果是运算符,则需要考虑三种情况:
 * 第一种:如果opStack栈为空,或者opStack栈顶运算符为(,则将该运算符压入该栈中
 * 第二种:让该运算符与opStack栈顶运算符进行比较优先级,如果该运算符的优先级大于等于opStack栈顶运算符,则将该运算符压入该栈中
 * 第二种:不满足以上两种情况,则将opStack栈顶的运算符弹出并压入numStack栈中,再次考虑这三种情况,直到满足前两种情况中的某一个情况为止
 * 5.如果遇到括号:如果是"(",则直接压入opStack中;如果是“)”,则依此弹出opStack栈中的运算符,并压入numStack中,直到遇到左括号为止,并将这两个括号舍弃
 * 6.当表达式遍历完毕,结束
 * 7,将opStack栈中的运算符依次弹出,并压入numStack栈中
 * 8.将数据反转即可

2.代码

package com.company;

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

/**
 * @author:抱着鱼睡觉的喵喵
 * @date:2021/2/19
 * @description:
 */
public class InfixToSuffix {
    public static void main(String[] args) {
        String str = "4 * ( ( 3 + 8 ) - 6 )";
        List<String> list = transform(str);
        System.out.println("中缀表达式转后缀表达式如下:");
        for (String temp : list) {
            System.out.printf("%s ", temp);
        }
        System.out.println();
        int result = cal(list);
        System.out.printf("结果为:%d",result);
    }

    /**
     * 中缀表达式转后缀表达式步骤
     * 1.定义两个栈,数据栈numStack和运算符栈opStack
     * 2.从左到右遍历中缀表达式
     * 3.如果是数字则压入numStack数据栈中
     * 4.如果是运算符,则需要考虑三种情况:
     * 第一种:如果opStack栈为空,或者opStack栈顶运算符为(,则将该运算符压入该栈中
     * 第二种:让该运算符与opStack栈顶运算符进行比较优先级,如果该运算符的优先级大于等于opStack栈顶运算符,则将该运算符压入该栈中
     * 第二种:不满足以上两种情况,则将opStack栈顶的运算符弹出并压入numStack栈中,再次考虑这三种情况,直到满足前两种情况中的某一个情况为止
     * 5.如果遇到括号:如果是"(",则直接压入opStack中;如果是“)”,则依此弹出opStack栈中的运算符,并压入numStack中,直到遇到左括号为止,并将这两个括号舍弃
     * 6.当表达式遍历完毕,结束
     * 7,将opStack栈中的运算符依次弹出,并压入numStack栈中
     * 8.将数据反转即可
     *
     * @param s
     * @return  转为后缀表达式之后的list集合
     */
    public static List<String> transform(String s) {
        Stack<String> numStack = new Stack<>();     //数据栈
        Stack<String> opStack = new Stack<>();      //运算符栈
        String str = "";
        String[] split = s.split(" ");          //以空格将数据分割
        for (int i = 0; i < split.length; i++) {       //遍历分割后的数据
            str = split[i];
            if (isOperator(str)) {      //如果是操作符
                if (str.equals(")")) {      //如果是右括号的情况
                    while (!opStack.peek().equals("(")) {
                        numStack.push(opStack.pop());
                    }
                    opStack.pop();          //丢弃右括号
                    continue;
                }
                while (true) {
                    if (opStack.isEmpty() || opStack.peek().equals("(")) {
                        opStack.push(str);
                        break;
                    } else if (priority(str) >= priority(opStack.peek())) {
                        opStack.push(str);
                        break;
                    } else {
                        numStack.push(opStack.pop());
                    }
                }
            } else if (str.matches("\\d+")) {       //如果是数字
                numStack.push(str);
            } else {
                throw new RuntimeException("你定义的表达式有误!~");
            }
        }
        while (!opStack.isEmpty()) {    //遍历结束,将运算符栈中的运算符加入到数据栈中
            numStack.push(opStack.pop());
        }
        List<String> list = new ArrayList<>(); //   存入list集合中
        while (!numStack.isEmpty()) {
            list.add(numStack.pop());
        }
        Collections.reverse(list);      //反转list
        return list;
    }

    /**
     * 判断是否是运算符
     *
     * @param s
     * @return
     */
    public static boolean isOperator(String s) {
        return s.equals("*") || s.equals("/") || s.equals("+") || s.equals("-") || s.equals("(") || s.equals(")");
    }

    /**
     * 使用0 1 2定义优先级
     *
     * @param s
     * @return
     */
    public static int priority(String s) {
        if (s.equals("*") || s.equals("/")) {
            return 1;
        } else if (s.equals("+") || s.equals("-")) {
            return 0;
        } else if (s.equals("(")) {
            return 2;
        } else {
            throw new RuntimeException("表达式有误!");
        }
    }

    /**
     * 计算表达式的结果
     * @param list
     * @return result
     */
    public static int cal(List<String> list) {
        Stack<String> stack = new Stack<>();
        int num1 = 0;
        int num2 = 0;
        int result;
        for (String ele : list) {
            if (ele.matches("\\d+")) {      //匹配的是一位数或者多位数(\d+)
                stack.push(ele);
            } else {
                result = 0;
                num1 = Integer.parseInt(stack.pop());
                num2 = Integer.parseInt(stack.pop());
                if (ele.equals("+")) {
                    result = num2 + num1;
                } else if (ele.equals("-")) {
                    result = num2 - num1;
                } else if (ele.equals("*")) {
                    result = num2 * num1;
                } else if (ele.equals("/")) {
                    result = num2 / num1;
                } else {
                    throw new RuntimeException("运算符有误!");
                }
                stack.push(""+result);
            }
        }
        return Integer.parseInt(stack.pop());
    }
}

愿你孤独的努力都有回报,愿你前行的路上有人陪伴~
加油~

posted on 2021-02-20 22:00  凸凸大军的一员  阅读(654)  评论(0编辑  收藏  举报