栈的应用-四则运算表达式求值

3 篇文章 0 订阅

Java实现四则运算表达式求值


前言

最近在复习数据结构与算法,在栈的应用中了解到计算机计算四则运算表达式的算法。

计算机计算四则运算主要分两步:

  1. 将中缀表达式转化为后缀表达式;
  2. 将后缀表达式进行运算得出结果。

后缀(逆波兰)表达式

后缀表达式是一种不包含括号,运算符放在两个运算对象的后面的表示法,比如四则运算表达式9+(3-1)*3+10/2,其后缀表达式为9 3 1 - 3 * + 10 2 / +。这是计算机采用的形式,计算过程如下:

9 3 1 - 3 * + 10 2 / +

9 2 3 * + 10 2 / +

9 6 + 10 2 / +

15 10 2 / +

15 5 +

20

方法就是:从左到右,将运算符前面的两个数,分别做为运算数和被运算数,如:3 1 - 就等于(3-1)=2,依次进行计算。

中缀转后缀

怎样将中缀表达式转成后缀表达式?

中缀表达式 “9+(3-1)*3+10/2” 转化为后缀表达式 “9 3 1 - 3 * + 10 2 / +”

数字输出,运算符进栈,括号匹配出栈,栈顶优先级不低出栈

规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出;是开括号‘(’,直接入栈;若是闭括号‘)’,则依次出栈,匹配前一个开括号;若栈顶运算符的优先级大于或等于当前运算符,栈顶出栈。

具体过程:

  1. 第一个字符9是数字,输出“9”,后面是符号“+”,入栈;

  2. 后面是开括号“(”,直接入栈;

  3. 然后是数字3,输出,表达式变为“9 3”,接着是“-”入栈,然后是数字1,输出,表达式为“9 3 1”;

  4. 接下来是闭括号“)”,需要去匹配前面的“(”,栈顶依次出栈,并输出。因此”-“出栈并输出,表达式为“9 3 1 -”,“(”出栈;

  5. 然后是符号“*”,因为栈顶“+”优先级低于“*”,所以“*”入栈,后面数字3输出,表达式变为“9 3 1 - 3”;

  6. 之后是符号“+”,因为栈顶“*”优先级高于“+”,所以栈中元素出栈(因为没有比“+”更低的优先级,所以全部出栈),表达式变为“9 3 1 - 3 * +”,当前符号“+”入栈;

  7. 接着数字10,输出,表达式变为“9 3 1 - 3 * + 10”;
  8. 然后“/”优先级高于栈顶“+”,入栈;

  9. 最后是数字2,输出,表达式为“9 3 1 - 3 * + 10 2”;

  10. 已经到了最后,所以将栈中符号全部出栈并输出。最终输出后缀表达式为“9 3 1 - 3 * + 10 2 / +”

计算后缀表达式

中缀转后缀是将符号进出栈,计算后缀表达式就需要将数字进出栈。

规则就是将数字依次入栈,遇到运算符就出栈两次,将栈顶元素分别作为被运算数和运算数进行计算,然后将计算结果入栈,直到表达式遍历完成,运算结束,栈中存在的唯一元素就是表达式的值。

代码实现:

import java.util.Scanner;
import java.util.Stack;

public class JavaTest {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String infix = in.nextLine();
        in.close();
        String postfix = trans2postfix(infix);// 得到后缀表达式
        System.out.println("postfix : " + postfix);
        int count = calculate(postfix);
        System.out.println("count = " + count);
    }

    // 计算后缀表达式
    private static int calculate(String postfix) {
        Stack<Integer> stack = new Stack<>();
        char[] arr = postfix.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            char current = arr[i];// 当前字符
            if (Character.isDigit(current)) {// 如果是数字,入栈
                stack.push(current - 48);
            } else {
                int n1 = stack.pop();
                int n2 = stack.pop();
                int m = 0;
                switch (current) {
                case '+':
                    m = n2 + n1;
                    break;
                case '-':
                    m = n2 - n1;
                    break;
                case '*':
                    m = n2 * n1;
                    break;
                case '/':
                    m = n2 / n1;
                    break;
                default:
                    break;
                }
                stack.push(m);
            }
        }
        return stack.get(0);
    }

    // 中缀转后缀
    public static String trans2postfix(String infix) {
        StringBuilder sb = new StringBuilder();
        Stack<Character> stack = new Stack<>();
        char[] arr = infix.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            char current = arr[i];// 当前字符
            if (Character.isDigit(current)) {// 如果是数字
                sb.append(current);
            } else {
                if (stack.isEmpty()) {// 如果栈为空,直接入栈
                    stack.push(current);
                } else {
                    if (current == ')') {// 闭括号
                        while (true) {
                            char top = stack.pop();
                            if (top != '(') {
                                sb.append(top);
                            } else {
                                break;
                            }
                        }
                    } else {
                        if (current != '(') {// 开括号,直接入栈
                            while (comparePriority(current, stack.peek()) <= 0) {// 当前优先级不比栈顶高,出栈
                                char top = stack.pop();
                                sb.append(top);
                                if (stack.isEmpty()) {
                                    break;
                                }
                            }
                        }
                        stack.push(current);
                    }
                }
            }
        }
        while (stack.size() != 0) {
            sb.append(stack.pop());
        }
        return sb.toString();
    }

    // 比较运算符优先级
    private static int comparePriority(char arg0, char arg1) {
        int pri0 = getPriority(arg0);
        int pri1 = getPriority(arg1);
        if (pri0 < pri1) {
            return 1;
        } else if (pri0 == pri1) {
            return 0;
        } else {
            return -1;
        }
    }

    // 获取运算符优先级
    private static int getPriority(char arg0) {
        switch (arg0) {
        case '*':
        case '/':
            return 3;
        case '+':
        case '-':
            return 4;
        default:
            return 0xF;
        }
    }
}

运行结果:

实现过程中遇到一个问题,使用char字符会将整数切成10以内的数字,比如10会变成1和0,而且后缀表达式也没有做字符间隔,比如931无法区别是9、3、1还是93、1或者931,所以上面的代码只能计算10以内的四则运算。优化可以将char改成int,并且输出要加上间隔。

能力有限,如有不足,请多指教。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值