表达式求值详解​​​​​​​

简书:表达式求值详解

   表达式求值时对数据结构中栈结构的灵活应用,对于一个表达式而言,它由操作数和运算符组合而成,我们现实中常见的表达式:A+B-C,类似这种格式的我们称之为中缀表达式,但是,计算机的计算方式是有别于人的,所以,我们可以先将表达式转换为后缀表达式,再对后缀表达式进行计算,这个过程就是我们常用的表达式求解的过程。

首先,我们要解决的问题是如何将中缀表达式转换成后缀表达式。下面是相关算法:

遍历表达式,

① 从左向右依次取得字符ch并进行判断

②如果ch为操作数,则直接将该操作数拼接到后缀表达式output中(初始状态为"")。

③如果ch为运算符,则进行以下操作:

     a、如果data='(',直接将'('入运算符栈。

     b、如果data=')',依次弹出运算符栈中的栈顶元素,知道弹出'('为止。

     c、如果不是a、b两种情况,则将ch与栈顶元素比较优先级

            如果ch优先级高,或者栈为空,那么直接将ch入栈

            否则,先将栈顶元素弹到output上,再将ch入栈

④如果,字符串遍历结束后,运算符栈不为空,则依次将栈顶元素弹出到output上。

实例 a+b-c

读取a,为操作数,output=a

读取+,为运算符,属于情况c,直接入栈

读取b,为操作数,output=ab

读取-,为运算符,属于情况c,将栈顶元素弹出,再将-压栈,output=ab+

读取c,为操作数,output=ab+c

遍历结束,栈不为空,依次弹出

output=ab+c-

 

当表达式转换成后缀表达时,计算将变得非常简单,下面是计算后缀表达式的算法:

1,设置一个栈用于存储操作数,栈初始化为空,然后从左到右扫描后缀表达式。

2,若ch为操作数,则进栈

     若ch为运算符,则从栈中退出两个元素,先退出的放到运算符的左边,后弹出的放到运算符的右边,进行计算,并将运算结果压入栈中。

3,直到后缀表达式扫描结束,此时栈中只剩下一个元素,即为运算结果。

 

程序源码如下:

package zp.javastudy.jisuanqi;

import java.util.Stack;

public class JiSuanQi {

    private String output = ""; // 后缀表达式
    private Stack<Character> operasta = new Stack<>(); // 运算符栈
    private Stack<Integer> numSta = new Stack<>(); // 数字栈
    private String[] strs;

    public static void main(String[] args) {
        JiSuanQi j = new JiSuanQi();
        j.change("(13%12)*33+4-54/6");
        System.out.println(j.count());
        // System.out.println(j.change("(22-14)*3+4-5/6"));
    }

    // 将中缀表达式转换为后缀表达式
    public void change(String el) {
        strs = el.split("[()/%+*-]"); // 使用正则表达式 将表达式中数字提取出来

        int pos = 0;
        // 遍历字符串
        for (int i = 0; i < el.length(); i++) {
            if (distinguish(el.charAt(i)) == 1) {
                // 获得数字
                while (strs[pos].equals("")) { // 当前分割后的字符串数组为""时,pos++
                    pos++;
                }
                output = output + strs[pos];
                // 当数字为为多位数时
                if (strs[pos].length() > 1) {
                    i = i + strs[pos].length() - 1;
                }
                pos++;

            } else { // 字符为运算符时
                if (el.charAt(i) == '(') {
                    operasta.push(el.charAt(i));
                }

                if (el.charAt(i) == ')') {
                    while (operasta.peek() != '(') { // 当栈顶元素为'(',终止循环
                        output = output + operasta.pop(); // 将栈顶元素与output进行拼接
                    }
                    operasta.pop(); // 将'('弹出操作符栈
                }

                if (el.charAt(i) != '(' && el.charAt(i) != ')') {
                    // 当字符串当前运算符优先级大于操作符栈顶元素字符串时
                    if (operasta.isEmpty()
                            || getlevel(el.charAt(i)) > getlevel(operasta
                                    .peek())) {
                        operasta.push(el.charAt(i)); // 将当前操作符入栈
                    } else {
                        output = output + operasta.pop(); // 先将栈顶元素拼接到后缀表达式中
                        operasta.push(el.charAt(i)); // 再将当前操作符入栈
                    }
                }
            }
        }

        // 遍历完字符串后,如果栈中还有运算符,则将其拼接到后缀表达式上
        while (!operasta.isEmpty()) {
            output = output + operasta.pop(); // 先将栈顶元素拼接到后缀表达式中
        }

        return;
    }

    // 计算后缀表达式
    public int count() {
        System.out.println(output);
        int pos = 0;
        for (int i = 0; i < output.length(); i++) {
            if (distinguish(output.charAt(i)) == 1) { // 数字
                // 获得数字
                while (strs[pos].equals("")) { // 当前分割后的字符串数组为""时,pos++
                    pos++;
                }
                numSta.push(Integer.parseInt(strs[pos])); // 将数字入栈
                // 当数字为为多位数时
                if (strs[pos].length() > 1) {
                    i = i + strs[pos].length() - 1;
                }
                pos++;
            } else {
                if (numSta.size() == 1) {
                    return numSta.pop();
                }
                numSta.push(countdetail(numSta.pop(), numSta.pop(),
                        output.charAt(i)));

            }
        }

        return numSta.pop();
    }

    // 具体的计算过程
    public int countdetail(int b, int a, char op) { // 注意前后顺序
        int ans = 0;
        switch (op) {
        case '+':
            ans = a + b;
            break;
        case '-':
            ans = a - b;
            break;
        case '*':
            ans = a * b;
            break;
        case '/':
            ans = a / b;
            break;
        case '%':
            ans = a % b;
            break;
        default:
            break;
        }
        // System.out.println(ans);
        return ans;
    }

    // 比较优先级
    public int getlevel(char ch) {
        int level = 0;
        switch (ch) {
        case '+':
            level = 1;
            break;
        case '-':
            level = 1;
            break;
        case '*':
            level = 2;
            break;
        case '/':
            level = 2;
            break;
        case '%':
            level = 2;
            break;
        default:
            break;
        }

        return level;
    }

    // 区分数字和操作符
    public int distinguish(char ch) {
        // 如果为数字则返回1 否则返回2
        if (ch >= '0' && ch <= '9') {
            return 1;
        } else {
            return 2;
        }
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值