关于逆波兰算法进行公式单位的推导

关于逆波兰算法的链接如下逆波兰算法
原理:将一个长表达式转化为2个数字之间的运算。
需求:利用逆波兰算法,推导出一个字母长表达式的单位


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

public class ReversePolish4Unit {

    private List<String> sList = new ArrayList<String>();// 中缀表达式集合
    private List<Object> dList = new ArrayList<Object>();// 后缀表达式集合
    private Stack<String> opStack = new Stack<String>();// 操作符栈
    private Stack<Object> rStack = new Stack<Object>();// 结果运算栈
    private final int level1 = 0;// +-的级别是0
    private final int level2 = 1;// */的级别是1
    private final int level3 = 3;// 左右括号是3
    private static Map<String, List> unit = new HashMap<String, List>() {
        private static final long serialVersionUID = 1L;
        List<String> oneClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("zhangsan");
            }
        };
        List<String> towClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("lisi");
            }
        };
        List<String> threeClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("wangwu");
            }
        };
        List<String> fourClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("liuliu");
            }
        };
        List<String> fiveClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("luncy");
            }
        };
        List<String> sixClass = new ArrayList<String>() {
            private static final long serialVersionUID = 1L;
            {
                add("dive");
                add("lulu");
                add("luckly");
            }
        };
        {
            put("one", oneClass);
            put("tow", towClass);
            put("three", threeClass);
            put("four", fourClass);
            put("five", fiveClass);
            put("six", sixClass);
        }
    };

    // 初始化
    public ReversePolish4Unit(String input) throws Exception {

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

    // 1.将中缀表达式转换为后缀表达式
    private List<Object> convertToReversePolish() throws Exception {
        for (String A : sList) {
            // 如果是单位,则直接存入dList
            if (A.matches("(^\\d+$)|five|four")) {
                ArrayList<String> divisorList = new ArrayList<String>();// 除数(分母)
                ArrayList<String> dividendList = new ArrayList<String>();// 被除数(分子)
                ArrayList<String>[] unitArray = new ArrayList[] { dividendList, divisorList };
                dList.add(unitArray);
            }
            // 如果是操作符
            else if (isOperate(A)) {
                opstack(A);
            } else if (isUnit(A)) {
                ArrayList<String> divisorList = new ArrayList<String>();// 除数(分母)
                ArrayList<String> dividendList = new ArrayList<String>();// 被除数(分子)
                dividendList.add(A);
                ArrayList<String>[] unitArray = new ArrayList[] { dividendList, divisorList };
                dList.add(unitArray);
            } else {
                return null;
            }
        }
        // 将栈清空
        while (!opStack.empty()) {
            dList.add(opStack.pop());
        }
        return dList;
    }

    /**
     * 对操作符号进行处理
     * 
     * @param dList
     * @param op
     */
    private void opstack(String op) {
        // 如果是空栈,则直接压入
        if (opStack.empty()) {
            opStack.push(op);
            return;
        }

        // 如果是左括号直接入栈
        if ("(".equals(op)) {
            opStack.push(op);
            return;
        }

        // 如果op 是右括号则对栈内元素进行出栈操作,直到遇到左括号
        if (")".equals(op)) {
            String tmp = "";
            while (!"(".equals(tmp = opStack.pop())) {
                dList.add(tmp);
            }
            return;
        }

        // 如果栈顶是左括号,当前操作符号直接入栈
        if ("(".equals(opStack.peek())) {
            opStack.push(op);
            return;
        }

        // 如果当前操作符的优先级高于栈顶元素,直接入栈
        if (comparePriority(op, opStack.peek())) {
            opStack.push(op);
            return;
        }

        // 如果当前元素的优先级低于栈顶元素的优先级
        if (!comparePriority(op, opStack.peek())) {
            // 如果栈顶不是左括号则进行出栈操作
            dList.add(opStack.pop());
            opstack(op);
        }
    }

    // 判断是不是单位
    private boolean isUnit(String num) {
        return num.matches("([\u4e00-\u9fa5]+)");
    }

    // 判断是不是操作符
    private boolean isOperate(Object op) {
        if (op instanceof String) {
            return op.toString().matches("[\\+\\-\\*\\/\\(\\)]");
        }
        return false;
    }

    // 判断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;
    }

    // 2.对后缀表达式进行计算
    private Object calculateReversePolish() throws Exception {

        for (Object A : dList) {
            if (isArray(A))
                rStack.push(A);
            // 如果是操作符
            else if (isOperate(A))
                calculate(A.toString());
        }
        // 栈中最后一个元素就是计算结果
        return rStack.pop();
    }

    private boolean isArray(Object a) {
        if (a instanceof ArrayList[]) {
            return true;
        }
        return false;
    }

    // 取两个操作数进行运算,并将运算结果入栈
    private void calculate(String op) throws Exception {
        ArrayList<String>[] d2 = (ArrayList<String>[]) rStack.pop(); // 旧操作数
        ArrayList<String>[] d1 = (ArrayList<String>[]) rStack.pop(); // 新操作数
        if ("*".equals(op)) {
            d1[0].addAll(d2[0]);
            d1[1].addAll(d2[1]);
        } else if ("/".equals(op)) {
            d1[0].addAll(d2[1]);
            d1[1].addAll(d2[0]);
        } else if ("+".equals(op) || "-".equals(op)) {
            if ((compareList(d1[0], d2[0]) && compareList(d1[1], d2[1])) || compareList(d2[0], d2[1])) {
            } else {
                throw new Exception("表达式有误");
            }
        }
        differenceSet(d1);
        rStack.push(d1);
    }

    /**
     * 判断两个List是否相同
     * 
     * @param args
     * @throws Exception
     */
    public synchronized <T extends Comparable<T>> boolean compareList(List<T> a, List<T> b) {
        if (a.size() != b.size())
            return false;
        Collections.sort(a);
        Collections.sort(b);
        for (int i = 0; i < a.size(); i++) {
            if (!a.get(i).equals(b.get(i)))
                return false;
        }
        return true;
    }

    public static String getUnit(String str) throws Exception {
        str = str.replaceAll("SUM\\(([^()+\\-*/]+)\\)", "$1");
        ReversePolish4Unit rp = new ReversePolish4Unit(str);
        List<Object> list = rp.convertToReversePolish();
        if (list == null) {
            return "ERROR";
        }
        return rp.returnUnit((ArrayList<String>[]) rp.calculateReversePolish());
    }

    /**
     * 返回单位
     * 
     * @param result
     * @return
     * @throws Exception
     */

    public String returnUnit(ArrayList<String>[] result) throws Exception {
        if (compareList(result[0], result[1])) {
            return "%";
        } else {
            if (result[1].size() < 2 && result[0].size() >= result[1].size()) {
                if (result[1].size() == 0 && result[0].size() > 0) {
                    return result[0].get(0);
                } else {
                    return result[0].get(0) + "/" + result[1].get(0);
                }
            } else {
                return "ERROR";
            }
        }
    }

    /**
     * 将计算表达式替换成单位表达式
     * 
     * @throws Exception
     */
    public String convert2UnitExpress(String str) throws Exception {
        if (isOperate(str)) {
            return str;
        }
        for (Entry<String, List> entry : unit.entrySet()) {
            if ((entry.getValue()).contains(str)) {
                return entry.getKey();
            }
        }
        if (str.matches("\\d+")) {
            return "";
        }
        return "ERROR";
    }

    /**
     * 移除两个List中相同的选项,不删除多余的
     * 
     * @param array
     */

    public void differenceSet(ArrayList<String>[] array) {
        for (int i = 0; i < array[0].size(); i++) {
            for (int j = 0; j < array[1].size(); j++) {
                if (array[0].get(i).equals(array[1].get(j))) {
                    String temp = array[0].get(i);
                    array[0].remove(temp);
                    array[1].remove(temp);
                    break;
                }
            }
        }
    }

    public static void main(String args[]) throws Exception {

        // Pattern pt = Pattern.compile("SUM\\(([^()+\\-*/]*)\\)");
        Pattern pt = Pattern.compile("(^\\d+|(\\s&&[^\\f\\n\\r\\t\\v])*$)");
        /*
         * Matcher mt = pt.matcher(str); while (mt.find()) {
         * System.out.println(mt.group(0)); // System.out.println(mt.group(1));
         * return; }
         */

        System.out.println(getUnit("lulu/lucky-1"));

        /*
         * if (str.matches("^\\d+|(\\s&&[^\\f\\n\\r\\t\\v])*$")) {
         * System.out.println("11"); } else { System.out.println("23"); }
         */

    }

}

备注:代码有修改,可能跑不起来,上述代码只提供思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值