表达式解释(能处理负号,用Java实现)

问题描述

程序设计中经常使用表达式,现在需要编写程序,设计算法,利用栈,计算合法表达式结果。本题中表达式由含运算符+、-、*、/、(、)和整形常量复合而成。

程序代码

package com.company;

import java.util.Scanner;
import java.util.Stack;
public class Main {
    public static String convert2Postfix(String infix) {
        char[] chars = infix.toCharArray();     //转换为字符数组
        Stack<Character> stack = new Stack<Character>();    //存放操作符
        StringBuilder ans = new StringBuilder(infix.length());      //存放后缀表达式。用stringBuilder方便拼接
        Character ch;
        for (int i=0;i<chars.length;i++) {
            Character c = chars[i];
            switch (c) {
                case '(':
                    stack.push(c);
                    break;      //左括号直接入栈
                case '*':
                case '/':
                    while (!stack.isEmpty()) {
                        ch = stack.pop();
                        if (getPriority(ch) < 2) {      //为 + - 操作或者 ( 的时候
                            stack.push(ch);
                            break;
                        } else ans.append(" " + ch);
                    }
                    stack.push(c);
                    ans.append(" ");
                    break;
                case '+':
                case '-':
                    Boolean a2 = (i != 0) && (c == '-') && (Character.isDigit(chars[i - 1]));     //表示-号前面为数字的时候
                    Boolean a3 = (i != 0) && (c == '-') && (chars[i - 1] == ')');       //表示-号前面为)的时候
                    Boolean a4 = (i != 0) && (c == '-') && (chars[i - 1] == '(');
                    if(a2.booleanValue() || a3.booleanValue() || c == '+') {      //表示这是操作符意义上的-号或者这是加号
                        while (!stack.isEmpty()) {
                            ch = stack.pop();
                            if (ch == '(') {        //+-的时候优先级比它低的只有(
                                stack.push('(');
                                break;
                            }
                            ans.append(" " + ch);
                        }
                        stack.push(c);
                        ans.append(" ");
                        break;
                    }else if(a4.booleanValue() || Character.isDigit(chars[i + 1])) {   //@更新之处:此时一定是(-23)这样的,我们当然是直接把符号加在字符串末尾,那么就能和后面的数字直接解释成负数
                        ans.append("-");
                    }else {     //@更新之处:此时一定是减号-(,且表达式一开始就是减号-,找到被()包括起来的数字
                        ans.append("0 ");
                        StringBuilder tmp = new StringBuilder();
                        int j;
                        for(j=i+1;j<chars.length;j++) {
                            tmp.append(chars[j]);
                            if(chars[j] == ')') {
                                break;
                            }
                        }
                        i = j;
//                        System.out.println("I am tmp " + tmp);
                        ans.append(convert2Postfix(tmp.toString()) + " -");
                    }
                case ')':
                    while(!stack.isEmpty()){
                        ch = stack.pop();
                        if(ch =='(')
                            break;
                        else
                            ans.append(" " + ch);
                    }       //直到出现(号停止弹出
                    break;
                default:
                    ans.append(c);  //普通数字字符直接拼接到后缀表达式里面
            }
        }
        while (!stack.empty()) {
            ans.append(" " + stack.pop());
        }
        return ans.toString();
    }

    public static int getPostfixValue(String postfix) {
        String[] tokens = postfix.split(" ");    //将后缀表达式按照空格分开
//        System.out.println(postfix);
        Stack<Integer> stack = new Stack<Integer>();
        int value = 0;
        int factor = 1;
        for (String c : tokens) {
            if (c.length() != 1 || Character.isDigit(c.charAt(0))) {      //如果长度不等于1(包括-1)或者说长度为1的数就压入到栈里
                stack.push(Integer.parseInt(c));
            } else if (c.length() == 1 && isOperator(c.charAt(0))) {      //为操作符的时候
                int op1 = stack.pop();
                int op2 = stack.pop();
                int result;
                switch (c.charAt(0)) {
                    case '*':
                        result = op1 * op2;
                        stack.push(result);
                        break;
                    case '/':
                        result = op2 / op1;
                        stack.push(result);
                        break;
                    case '+':
                        result = op1 + op2;
                        stack.push(result);
                        break;
                    case '-':
                        result = op2 - op1;
                        stack.push(result);
                        break;
                }
            }
        }
        return stack.pop() * factor;
    }
    private static int getPriority(char operator) {
        int t = 0;
        if (operator == '-' || operator == '+') {
            t = 1;
        } else if (operator == '*' || operator == '/') {
            t = 2;
        }
        return t;
    }//获取优先级
    private static boolean isOperator(char x) {
        if(x == '-' || x == '+' || x == '*' || x == '/')
            return true;
        else
            return false;
    }//判断是否为操作符
    public static void main(String[] args)
    {
        Scanner cin = new Scanner(System.in);
        String expression = cin.nextLine();
        System.out.println(getPostfixValue(convert2Postfix(expression)));
    }//主程序
}

程序说明

将中缀表达式转换为后缀表达式后进行计算,以下引自百度百科

a. 若为 '(',入栈;

b. 若为 ')',则依次把栈中的的运算符加入后缀表达式中,直到出现'(',从栈中删除'(' ;

c. 若为 除括号外的其他运算符, 当其优先级高于除'('以外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号为止。

·当扫描的中缀表达式结束时,栈中的的所有运算符出栈;

转换成后缀表达式再进行相应计算,详见注释

更新日志

2021-1-28

  • 感谢评论区指出的一个小bug,问题在于如果出现-(1+2)这样的式子本来我是没有考虑到的
    • 处理的方案是在将中追表达式->后缀表达式的时候将其看成0-(1+2)这样再转化为对应的后缀表达式也就是0 1 2 + -,这样就能很好的处理这样的式子了
    • 转换的关键在于找到被()包括起来的部分的式子,这里是用for循环来找)
posted @ 2018-07-22 12:50  MartinLwx  阅读(1870)  评论(3编辑  收藏  举报