中缀表达式转后缀表达式以及简单后缀表达式的计算(考虑了多位数的情况,含括号)

中缀表达式转后缀表达式(考虑了多位数的情况)

需要用到的ascll码
*42
+43
-45
/47
(40
)41

思路

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

算法

/**
     * 中缀表达式转后缀表达式
     * @param expression
     * @return
     */
    public static String transfer(String expression) {
        //1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
        Stack<String> s1 = new Stack<>();//运算符栈
        Stack<String> s2 = new Stack<>();//储存中间结果的栈
        int index = 0;
        String keepNum = "";//用于拼接多位数
        //2.从左至右扫描中缀表达式;
        while (index  < expression.length()) {
            char c = expression.charAt(index);
            //3.遇到操作数时,将其压s2;
            if (c >= 48 && c <= 57) {
                //且数字为表达式最后一位,则直接入栈s2
                if(index+1 == expression.length()){
                    s2.push(String.valueOf(c));
                }
                keepNum += c;
                index++;
            }
            //4.如果字符c为运算符 分类讨论
            else if (c == 42 || c == 43 || c == 45 || c == 47) {
                s2.push(keepNum);
                keepNum = "";
                //4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
                if (s1.isEmpty() || "(".equals(s1.peek())) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
                else if (priority(c) > priority(s1.peek().charAt(0))) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
                else {
                    s2.push(s1.pop());
                }
            }
            //5.如果遇到括号
            //5.1如果是左括号“(",则直接压入s1,继续遍历
          else  if ('(' == c) {
                s2.push(keepNum);
                keepNum = "";
                s1.push(String.valueOf(c));
                index++;
            }
            //5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
           else if (')' == c) {
                s2.push(keepNum);
                keepNum = "";
                while (true) {
                    String pop = s1.pop();
                    if ("(".equals(pop)) {
                        break;
                    }
                    s2.push(pop);
                }
                index++;
            }
            //6.重复步骤2至5,直到表达式的最右边
        }
        //遍历结束后将s1中剩余的运算符依次弹出并压入s2,再逆序输出s2就得到了后缀表达式
        //7.将s1中剩余的运算符依次弹出并压入s2
        while(!s1.isEmpty()){
            String pop = s1.pop();
            s2.push(pop);
        }
        String suffixExpression = "";
        while (!s2.isEmpty()) {
            String pop = s2.pop();
            suffixExpression += pop + " ";
        }
        //根据空格分割
        String[] s = suffixExpression.split(" ");
        ArrayList<String> arrayList  =new ArrayList<>();
        //去除多余空格
        for (String s3 : s) {
            if(!"".equals(s3)){
                arrayList.add(s3);
            }
        }
        //8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
        Collections.reverse(arrayList);
        String s4 = "";
        for (String s3 : arrayList) {
            s4+=s3+" ";//此处又添加空格是为了方便给calculate函数计算,因为calculate函数需要有空格间隙的表达式
        }
        return s4;
    }

计算简单后缀表达式

思路

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素和栈顶元素),并将结果入栈;
重复上述过程直到表达式最右端,最后栈中的值即为表达式的结果

算法

/**
     * 计算后缀表达式
     * @param suffixExpression
     */
    public static void calculate(String suffixExpression) {
        String[] s = suffixExpression.split(" ");
        Stack<Integer> stack = new Stack<>();
        for (String s1 : s) {
            int i;
            //如果是运算符号,使用Integer.parseInt()会报NumberFormatException 以此来判断是不是运算符
            try {
                i = Integer.parseInt(s1);
            } catch (NumberFormatException e) {
                i = s1.charAt(0);
            }
            //如果是运算符
            if (i == 43 || i == 45 || i == 47 || i == 42) {
                Integer pop1 = stack.pop();
                Integer pop2 = stack.pop();
                int result = 0;
                switch (i) {
                    case 42:
                        result = pop1 * pop2;
                        stack.push(result);
                        break;
                    case 43:
                        result = pop1 + pop2;
                        stack.push(result);
                        break;
                    case 45:
                        result = pop2 - pop1;
                        stack.push(result);//除法(减法)需要用次顶元素除以(减)栈顶元素
                        break;
                    case 47:
                        result = pop2 / pop1;
                        stack.push(result);//除法(减法)需要用次顶元素除以(减)栈顶元素
                        break;
                    default:
                        break;
                }
            }
            //如果非运算符,就将数字入栈
            else {
                stack.push(i);
            }
        }
        Integer peek = stack.peek();
        System.out.println(peek);
    }

    //为运算符分配优先级
    public static int priority(char c) {
        if (c == '*' || c == '/') {
            return 1;
        }
        if (c == '-' || c == '+') {
            return 0;
        }
        if (c == '(' || c == ')') {
            return 2;
        }
        return -1;//传入的符号不是运算符
    }

根据算法思路结合代码,遇到疑问可以进行debug或者举简单例子进行画图理解

完整代码

package stack;

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

/**
 * @author Watching
 * * @date 2022/11/1
 * * Describe:
 * 一,中缀表达式转后缀表达式  (考虑了多位数的情况
 * 思路:
 * 1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
 * 2.从左至右扫描中缀表达式;
 * 3.遇到操作数时,将其压s2;
 * 4.遇到运算符时,分类讨论;
 * 4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
 * 4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
 * 4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
 * 5.遇到括号时:
 * 5.1如果是左括号“(",则直接压入s1
 * 5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
 * 6.重复步骤2至5,直到表达式的最右边
 * 7.将s1中剩余的运算符依次弹出并压入s2
 * 8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
 * <p>
 * <p>
 * 二,逆波兰表达式计算
 * 思路:
 * 从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次项元素和栈项元素),并将结果入栈;
 * 重复上述过程直到表达式最右端,最后栈中的值即为表达式的结果
 * <p>
 * <p>
 * 三,ascll码
 * * 42
 * + 43
 * - 45
 * / 47
 * ( 40
 * ) 41
 */
public class PolandNotation {
    public static void main(String[] args) {
//        String suffixExpression = "30 4 + 5 * 6 -";//(30+4)*5-6
//        calculate(suffixExpression);
        String expression = "(30+4)*5-6";
        String suffixExpression = transfer(expression);
        calculate(suffixExpression);
    }

    /**
     * 中缀表达式转后缀表达式
     * @param expression
     * @return
     */
    public static String transfer(String expression) {
        //1.初始化两个栈:运算符栈s1和储存中间结果的栈s2;
        Stack<String> s1 = new Stack<>();//运算符栈
        Stack<String> s2 = new Stack<>();//储存中间结果的栈
        int index = 0;
        String keepNum = "";//用于拼接多位数
        //2.从左至右扫描中缀表达式;
        while (index  < expression.length()) {
            char c = expression.charAt(index);
            //3.遇到操作数时,将其压s2;
            if (c >= 48 && c <= 57) {
                //且数字为表达式最后一位,则直接入栈s2
                if(index+1 == expression.length()){
                    s2.push(String.valueOf(c));
                }
                keepNum += c;
                index++;
            }
            //4.如果字符c为运算符 分类讨论
            else if (c == 42 || c == 43 || c == 45 || c == 47) {
                s2.push(keepNum);
                keepNum = "";
                //4.1如果s1为空,或栈项运算符为左括号“(”, 则直接将此运算符入栈;
                if (s1.isEmpty() || "(".equals(s1.peek())) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.2若运算符优先级比s1栈项运算符的高,也将运算符压入s1;
                else if (priority(c) > priority(s1.peek().charAt(0))) {
                    s1.push(String.valueOf(c));
                    index++;
                }
                //4.3否则,将s1栈项的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈项运算符相比较;
                else {
                    s2.push(s1.pop());
                }
            }
            //5.如果遇到括号
            //5.1如果是左括号“(",则直接压入s1,继续遍历
          else  if ('(' == c) {
                s2.push(keepNum);
                keepNum = "";
                s1.push(String.valueOf(c));
                index++;
            }
            //5.2如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
           else if (')' == c) {
                s2.push(keepNum);
                keepNum = "";
                while (true) {
                    String pop = s1.pop();
                    if ("(".equals(pop)) {
                        break;
                    }
                    s2.push(pop);
                }
                index++;
            }
            //6.重复步骤2至5,直到表达式的最右边
        }
        //遍历结束后将s1中剩余的运算符依次弹出并压入s2,再逆序输出s2就得到了后缀表达式
        //7.将s1中剩余的运算符依次弹出并压入s2
        while(!s1.isEmpty()){
            String pop = s1.pop();
            s2.push(pop);
        }
        String suffixExpression = "";
        while (!s2.isEmpty()) {
            String pop = s2.pop();
            suffixExpression += pop + " ";
        }
        //根据空格分割
        String[] s = suffixExpression.split(" ");
        ArrayList<String> arrayList  =new ArrayList<>();
        //去除多余空格
        for (String s3 : s) {
            if(!"".equals(s3)){
                arrayList.add(s3);
            }
        }
        //8.依次弹出s2中的元素并输出,结果的逆即为中缀表达式对应的后缀表达式
        Collections.reverse(arrayList);
        String s4 = "";
        for (String s3 : arrayList) {
            s4+=s3+" ";//此处又添加空格是为了方便给calculate函数计算,因为calculate函数需要有空格间隙的表达式
        }
        return s4;
    }

    /**
     * 计算后缀表达式
     * @param suffixExpression
     */
    public static void calculate(String suffixExpression) {
        String[] s = suffixExpression.split(" ");
        Stack<Integer> stack = new Stack<>();
        for (String s1 : s) {
            int i;
            //如果是运算符号,使用Integer.parseInt()会报NumberFormatException 以此来判断是不是运算符
            try {
                i = Integer.parseInt(s1);
            } catch (NumberFormatException e) {
                i = s1.charAt(0);
            }
            //如果是运算符
            if (i == 43 || i == 45 || i == 47 || i == 42) {
                Integer pop1 = stack.pop();
                Integer pop2 = stack.pop();
                int result = 0;
                switch (i) {
                    case 42:
                        result = pop1 * pop2;
                        stack.push(result);
                        break;
                    case 43:
                        result = pop1 + pop2;
                        stack.push(result);
                        break;
                    case 45:
                        result = pop2 - pop1;
                        stack.push(result);
                        break;
                    case 47:
                        result = pop2 / pop1;
                        stack.push(result);
                        break;
                    default:
                        break;
                }
            }
            //如果非运算符,就将数字入栈
            else {
                stack.push(i);
            }
        }
        Integer peek = stack.peek();
        System.out.println(peek);
    }

    //为运算符分配优先级
    public static int priority(char c) {
        if (c == '*' || c == '/') {
            return 1;
        }
        if (c == '-' || c == '+') {
            return 0;
        }
        if (c == '(' || c == ')') {
            return 2;
        }
        return -1;//传入的符号不是运算符
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值