堆实现数学表达式求值(利用逆波兰表达式)

1.表达式求值比较复杂,涉及到运算符的优先级,还有括号的影响,所以需要有一个合适的求值方法来完成,逆波兰式是个最佳选择,逆波兰式就是利用堆的特性来设计的。

2.利用堆实现数学表达式求值,代码中主要的方法是initRPN方法和caculate方法,initRPN方法的功能是将输入的表达式(中缀表达式)按照规则转换成后缀表达式(逆波兰表达式),caculate是将逆波兰表达式按照规则计算结果。


import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 逆波兰表达式的实现
 * 利用堆
 * 
 * 输入
 * String regex = "9+(3-1)*3+10/2";
 * 预期输出
 * String rpn_str = "931- 3*+102/+";
 *
 */
public class RPN {

    private static Map<String, Integer> optPriority = new HashMap<>();
    private static final String NONE = "none";

    /*这个是运算符的优先级,注意这里不要对括号排优先级,因为括号出现的场景不一样,运算符有可能进栈或者出栈,所以括号应当单独处理*/
    static {
        optPriority.put("+", 1);
        optPriority.put("-", 1);
        optPriority.put("*", 2);
        optPriority.put("/", 2);
        optPriority.put("=", 0);
        optPriority.put("none", -Integer.MAX_VALUE);//辅助值,用以处理为null的情况
    }

    public static void main(String[] args) {
        Stack<Object> rpn1 = initRPN();

        Stack<Object> rpn2 = new Stack<>();
        while (rpn1.top != null) {
            rpn2.push(rpn1.pop());
        }
        caculate(rpn2);
    }

    /**
     * 规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符
     * 号,就将处于栈顶两个数字出拢,进行运算,运算结果进栈, 一直到最终获得结果。
     * @param rpn
     */
    public static void caculate(Stack<Object> rpn) {
        Stack<Integer> statck = new Stack<>();

        if (rpn != null) {
            while (rpn.getTop() != null) {
                Object obj = rpn.pop();
                if (isDigit((String) obj)) {
                    statck.push(Integer.valueOf((String)obj));
                } else {
                    switch ((String) obj) {
                        case "+" : {
                            int num = statck.pop() + statck.pop();
                            statck.push(num);
                            break;
                        }
                        case "-" : {
                            int num = -statck.pop() + statck.pop();
                            statck.push(num);
                            break;
                        }
                        case "*" : {
                            int num = statck.pop() * statck.pop();
                            statck.push(num);
                            break;
                        }
                        case "/" : {
                            int a2 = statck.pop();
                            int a1 = statck.pop();
                            int num = a1 / a2;
                            statck.push(num);
                            break;
                        }
                    }
                }
            }
            System.out.println("result: " + statck.pop());
        }
    }

    /**
     * 将中缀表达式转换成后缀表达式(逆波兰表达式)
     * 规则 : 从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后
     * 缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低
     * 于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出 , 并将当前符号进栈,一直
     * 到最终输出后缀表达式为止。
     * @return
     */
    public static Stack<Object> initRPN() {
        Stack<Object> rpn = new Stack<>();
        Scanner sc = new Scanner(System.in);
        String e = sc.nextLine();
        Stack<String> opt = new Stack<>();
        while (true){
            if (!isDigit(e)){
                if ("(".equals(e)) {
                    opt.push(e);
                }
                if (")".equals(e)) {
                    String opt_top = opt.getTop() == null ? NONE : opt.pop();
                    while(!opt_top.equals("(")) {
                        rpn.push(opt_top);
                        opt_top = opt.pop();
                    }
                }
                if (!"(".equals(e) && !")".equals(e) && !"=".equals(e)) {
                    String opt_top = opt.getTop() == null ? NONE : opt.getTop();
                    while(true) {
                        if ("(".equals(opt_top)) {
                            opt.push(e);
                            break;
                        } else {
                            if (isBigger(e, opt_top)) {
                                opt.push(e);
                                break;
                            }
                            opt_top = opt.pop();
                            rpn.push(opt_top);
                            opt_top = opt.getTop() == null ? NONE : opt.getTop();

                        }
                    }

                }
            } else {
                rpn.push(e);
            }
            if (e.equals( "=")) {
                while (opt.getTop() != null) {
                    rpn.push(opt.pop());
                }
                break;
            }
            e = sc.nextLine();
        }
        return  rpn;
    }

    public static boolean isBigger(String e, String topOpt) {
        if (optPriority.get(e) > optPriority.get(topOpt))
            return  true;
        else
            return false;
    }

    //判断一个字符是否都为数字
    public static boolean isDigit(String strNum){
        return strNum.matches("[0-9]{1,}");
    }
}

class Stack<T> {
    Node<T> top;

    public void push(T data) {
        Node<T> newNode = new Node<>(data);
        newNode.next = this.top;
        this.top = newNode;
    }

    public T getTop() {
        T topData = this.top == null ? null : this.top.data;
        return topData;
    }

    public T pop() {
        if (this.top != null) {
            T data = this.top.data;
            this.top = this.top.next;
            return data;
        } else {
            System.out.println("堆空了!");
            return null;
        }
    }
}

class Node<T> {
    T data;
    Node<T> next;
    public Node(T data) {
        this.data = data;
    }
}

猜你喜欢

转载自blog.csdn.net/tab_yls/article/details/80998768
今日推荐