java实现中缀表达式转后缀表达式(逆波兰表达式)并求值

后缀表达式-逆波兰表达式

我们平日里习惯用的表达式一般为中缀表达式,而对于计算机而言,中缀表达式是一种比较复杂的计算结构,相反逆波兰表达式对于计算机而言则显得比较简单,因为计算机普遍采用的内存结构为先进后出的栈式内存结构。
举例说明:
中缀表达式: 3+2*5-6
后缀表达式: 3 2 5 * + 6 -

java实现中缀表达式转后缀表达式

步骤:

  1. 新建栈stack,用于保存表达式,新建集合List<String>,用于保存最终的后缀表达式
  2. 将输入的中缀表达式表达式转换为List<String>集合
  3. 遍历中缀表达式集合
    3.1 若为数字,直接放入最终的后缀表达式集合中
    3.2 若为表达式,分情况处理
    (1) 若表达式stack中为空或者表达式为"(",直接push进stack
    (2) 若表达式为")",需要循环处理stack中的顶部元素,并依次将顶部元素非"()"放入最终的后缀表达式集合中,并将")"移除
    (3) 若表达式的优先级低于stack中顶部元素的优先级(注意"()"没有优先级),需将stack顶部的表达式取出,放入最终的后缀表达式集合中,并将优先级低的表达式push进stack
    (4) 若表达式的优先级高于或等于stack中顶部元素的优先级,直接push进stack
    3.3 将stack中的表达式依次取出,添加进入最终的后缀表达式集合中

代码实现

import java.util.*;

/**
 * 栈
 * 实现逆波兰表达式算法,即后缀表达式
 * 1、给定一个中缀表达式,例如 2+3*2+6
 * 2、将中缀表达式转化为后缀表达式232*+6+  [2,3,2,*,+,6,+]
 * 3、计算后缀表达式为14
 */
public class CalculateStack {

    private static final List<String> EXPRESSION = Arrays.asList("+", "-", "*", "/", "(", ")");

    private static final int ADD = 1;
    private static final int SUBTRACT = 1;
    private static final int MULTIPLY = 2;
    private static final int DIVIDE = 2;
    private static final Map<String, Integer> PRIORITY = new HashMap<>();

    static {
        PRIORITY.put("+", ADD);
        PRIORITY.put("-", SUBTRACT);
        PRIORITY.put("*", MULTIPLY);
        PRIORITY.put("/", DIVIDE);
    }

    /**
     * 中缀表达式转后缀表达式
     * 步骤:
     * 1.新建栈stack,用于保存表达式,新建集合List<String>,用于保存最终的后缀表达式结果
     * 2.将输入的中缀表达式表达式转换为List<String>集合
     * 3.遍历中缀表达式集合
     *   3.1 若为数字,直接放入最终的后缀表达式集合中
     *   3.2 若为表达式,分情况处理
     *     3.2.1 若表达式stack中为空或者表达式为"(",直接push进stack
     *     3.2.2 若表达式为")",需要循环处理stack中的顶部元素,并依次将顶部元素非"()"放入最终的后缀表达式集合中,并将")"移除
     *     3.2.3 若表达式的优先级低于stack中顶部元素的优先级(注意"()"没有优先级),需将stack顶部的表达式取出,放入最终的后缀表达式集合中,并将优先级低的表达式push进stack
     *     3.2.4 若表达式的优先级高于或等于stack中顶部元素的优先级,直接push进stack
     *   3.3 将stack中的表达式依次取出,添加进入最终的后缀表达式集合中
     */
    private static List<String> convertToSuffExper(String infixExpression){
        Stack<String> exprStack = new Stack<>();
        List<String> list = new ArrayList<>();
        List<String> experList = convertExpToList(infixExpression);
        for (int i =0; i < experList.size(); i ++){
            String expression = experList.get(i);
            if (isNumber(experList.get(i))){
                list.add(experList.get(i));
            }else {
                if (exprStack.isEmpty() || "(".equals(expression) || ("(".equals(exprStack.peek()) && !")".equals(expression))){
                    exprStack.push(expression);
                    continue;
                }
                if ("(".equals(expression)){
                    exprStack.push(expression);
                    continue;
                }
                if (")".equals(expression)){
                    while (!"(".equals(exprStack.peek())){
                        list.add(exprStack.pop());
                    }
                    exprStack.pop();
                    continue;
                }
                if (PRIORITY.get(expression) < PRIORITY.get(exprStack.peek())){
                    list.add(exprStack.pop());
                    exprStack.push(expression);
                }else {
                    exprStack.push(expression);
                }
            }
        }
        while (!exprStack.isEmpty()){
            list.add(exprStack.pop());
        }
        System.out.println("转换成的后缀表达式为:" + list);
        return list;
    }

    /**
     * 将输入的中缀表达式表达式转换为List<String>集合
     * @return
     */
    private static List<String> convertExpToList(String infixExpression){
        if (infixExpression == null || "".equals(infixExpression)){
            throw new RuntimeException("输入的中缀表达式不能为空!");
        }
        infixExpression = infixExpression.replaceAll(" ", "");
        List<String> result = new ArrayList<>();
        for (int i =0; i < infixExpression.length(); i ++){
            if (!charIsNumber(infixExpression.charAt(i))){
                if (EXPRESSION.contains(infixExpression.charAt(i) + "")){
                    result.add(infixExpression.charAt(i) + "");
                }else {
                    throw new RuntimeException("表达式 " +infixExpression.charAt(i) + "" + "非法!");
                }
            }else {
                String str = "";
                while (charIsNumber(infixExpression.charAt(i))){
                    str += infixExpression.charAt(i);
                    if (i < infixExpression.length() -1 && charIsNumber(infixExpression.charAt(i +1))){
                        i ++;
                    }else {
                        break;
                    }
                }
                result.add(str);
            }
        }
        return result;
    }

    /**
     * 计算后缀表达式
     * @param suffixExpression 后缀表达式集合
     */
    public static void calculateSuffix(List<String> suffixExpression){
        Stack<String> numStack = new Stack<String>();//用于保存数字
        for (String str : suffixExpression){
            if (isNumber(str)){
                numStack.push(str);
            }else {
                int num1 = Integer.parseInt(numStack.pop());
                int num2 = Integer.parseInt(numStack.pop());
                int result = caclulateRes(num1, num2, str);
                numStack.push(result + "");
            }
        }
        System.out.println("最终计算的结果为:" + numStack.pop());
    }

    private static int caclulateRes(int num1, int num2, String experssion){
        int result;
        switch (experssion){
            case "+" :
                result = num1 + num2;
                break;
            case "-" :
                result = num2 - num1;
                break;
            case "*" :
                result = num2 * num1;
                break;
            case "/" :
                result = num2 / num1;
                break;
            default:
                throw new RuntimeException("表达式" + experssion + "有误");
        }
        return result;
    }

    /**
     * 判断是数字还是运算符
     * @param
     */
    private static boolean isNumber(String s){
        return s.matches("^-?[1-9]\\d*$");//是否为整数数字
    }

    /**
     * 判断是数字还是运算符
     * @param
     */
    private static boolean charIsNumber(char s){
        return s >=48 && s <=57;//是否为整数数字
    }


    public static void main(String[] args) {
        calculateSuffix(convertToSuffExper("(1+2)*((3*2))+6/2"));
    }
}

测试:
输入中缀表达式 : (1+2) * ((3 * 2))+6/2
转换为后缀表达式为: 1, 2, +, 3, 2, *, *, 6, 2, /, +
计算结果为: 21


image.png

欢迎留言,我们一起成长~~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容