手写逆波兰表达式-练习栈的使用

概念:
逆波兰表达式也叫后缀表示法,即操作符号都置于操作数的后面,逆波兰表达式可以不用括号来标识操作符的优先级。例如:3+4 是一个中缀表达式,转换成逆波兰表达式为34+ 。有人可能会想有后缀表达式,中缀表达式,那有没有前缀表达式呢?答案是:有前缀表达式,也叫波兰表达式,上文中的3+4 用前缀表达式表示为+34。

用途:
了解了什么是逆波兰表达式,那它有什么具体的用途呢?
1.逆波兰表达式中不需要括号,用户只需按照表达式顺序求值,让堆栈自动记录中间结果;同样的,也不需要指定操作符的优先级
2.机器状态永远是一个堆栈状态,堆栈里是需要运算的操作数,栈内不会有操作符。
3.当有操作符时就计算,因此,表达式并不是从右至左整体计算而是每次由中心向外计算一部分,这样在复杂运算中就很少导致操作符错误。
计算原理:
逆波兰表达式进行数据计算的时候一般分为两步:
1.将中缀表达式转换为后缀表达式
2.对转换完成后的后缀表达式进行计算

package com.jason.datastruct;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;

public class ReversePolish {
    private List<String> sList = new ArrayList<String>();// 中缀表达式集合
    private List<String> dList = new ArrayList<String>();// 后缀表达式集合
    private Stack<String> opStack = new Stack<String>();// 操作符栈
    private Stack<String> rStack = new Stack<String>();// 结果运算栈
    private final int level1 = 0;// +-的级别是0
    private final int level2 = 1;// */的级别是1
    private final int level3 = 3;// 左右括号是3

    // 初始化
    public ReversePolish(String input) {
        // a+b-c*(d+e) 转换为实际值例如:1+2-3*(4+5)
        StringTokenizer st = new StringTokenizer(input, "+-*/()", true);
        while (st.hasMoreTokens()) {
            sList.add(st.nextToken());
        }
    }

    public List<String> infix2ReversePolish() {
        for (String string : sList) {
            // 如果是数字 直接放入dlist 数组
            if (isNumber(string)) {
                dList.add(string);
            } else if (isOperation(string)) {
                // 如果是运算符 放入运算符栈

                opHandler(string);

            } else {
                System.out.println("非法操作符");

            }

        }
        // 将栈置空
        while (!opStack.empty()) {
            dList.add(opStack.pop());
        }
        return dList;
    }

    private void opHandler(String s) {

        for (Object string : opStack.toArray()) {
            System.out.print(string + "");
        }
        System.out.println();
        // 如果运算符栈是空 直接放入栈

        if (opStack.empty()) {
            opStack.push(s);
            return;
        }
        // 如果是(直接入栈
        if (s.equals("(")) {
            opStack.push(s);
            return;
        }
        // 如果是) 将(和)之间的出栈
        if (s.equals(")")) {
            while (!"(".equals(opStack.peek())) {
                dList.add(opStack.pop());
            }
            opStack.pop();
            // String tmp = "";
            // while (!"(".equals(tmp = opStack.pop())) {
            // dList.add(tmp);
            // }
            return;

        }

        // 如果栈顶是( 直接入栈

        if ("(".equals(opStack.peek())) {
            opStack.push(s);
            return;
        }
        // 如果运算符等级大于当前预算符 直接入栈

        if (comparePriority(s, opStack.peek())) {
            opStack.push(s);
            return;
        }
        // 如果等级小 或者等于 栈里的出栈 // 小的入栈 (在调用一次)
        if (!comparePriority(s, opStack.peek())) {
            dList.add(opStack.pop());
            opHandler(s);

        }

    }

    // 判斷是否是数字
    private boolean isNumber(String s) {
        return s.matches("\\d+");
    }

    // 判断是否是运算符
    private boolean isOperation(String s) {
        return s.matches("[\\+\\-\\*\\/\\(\\)]");
    }

    // 判断op1 的优先级 是否大于 op2的优先级
    private boolean comparePriority(String op1, String op2) {
        return getLevel(op1) > getLevel(op2);
    }

    // 获得操作符的优先级
    private int getLevel(String op) {
        if ("+".equals(op) || "-".equals(op)) {
            return level1;
        }
        if ("*".equals(op) || "/".equals(op)) {
            return level2;
        }
        if ("(".equals(op) || ")".equals(op)) {
            return level3;
        }
        return -1;
    }

    // 计算 反波兰表达式
    public String resultFromReversePolish() {
        for (String string : dList) {
            // 如果是数字 入栈
            if (isNumber(string)) {
                rStack.push(string);
            } else if (isOperation(string)) {
                // 如果是运算符 取出上面2个 进行运算 结果入栈
                if (string.equals("(") || string.equals(")")) {
                    return "公式错误";
                }
                int num2 = Integer.parseInt(rStack.pop());
                int num1 = Integer.parseInt(rStack.pop());
                String result = operation(num1, string, num2);
                rStack.push(result);
            }
        }
        if (rStack.empty()) {
            return "";
        }
        return rStack.pop();
    }
    //运算
    private String operation(int num1, String string, int num2) {

        switch (string) {
        case "+":
            return num1 + num2 + "";
        case "-":

            return num1 - num2 + "";

        case "*":

            return num1 * num2 + "";

        case "/":
            return num1 / num2 + "";

        default:
            return "";
        }

    }

}

测试类:

package com.jason.datastruct;

import java.util.ArrayList;

public class ReversePolishTest {

    public static void main(String[] args) {

        String str="1+((2-3)*(4+5))+((6/2))";
        System.out.println("中缀表达式:"+str);
        ReversePolish rPolish=new ReversePolish(str);

        ArrayList<String> reversePolish =(ArrayList<String>) rPolish.infix2ReversePolish();
        System.out.println("转换 逆波兰表达式:");
        for (String string : reversePolish) {
            System.out.print(string+",");
        }
        //1,2,3,4,-,*,6,*,+,7,-,
        System.out.println();
        System.out.println("结果\t:"+rPolish.resultFromReversePolish());
    }
}

结果:

中缀表达式:1+((2-3)*(4+5))+((6/2))

+
+(
+((
+((-
+(
+(*
+(*(
+(*(+
+(*
+

+
+(
+((
+((/
+(
转换 逆波兰表达式:
1,2,3,-,4,5,+,*,+,6,2,/,+,
结果  :-5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值