package com.hblg.guigu.stack;


import java.util.ArrayList;
import java.util.List;

/**
 * @author i
 * @create 2019/9/27 10:19
 * @Description  逆波兰表达式
 *  (3+4)*5-6 对应的后缀表达式就是3 4 + 5 * 6 -
 *  1.从左到右扫描 如果是数就存储到栈中
 *  2.如果是符号 就将当前栈的最高 和次高的数据 依次取出 用当前的符号 进行算数运算。
 *
 */
public class PolandNotaion {

    public static void main(String[] args) {
        //String suffixExpression = "3 4 + 5 * 6 -";//
        //System.out.println(getExpressionValue(getStrList(suffixExpression)));
        String expression = "1+((2+3)*4)-5";
        System.out.println(getExpressionValue(parseSuffixExpreesionList(toInfixExpressionList(expression))));

    }


    /***
     * 创建两个栈 一个用来存储存储运算符s1 另一个存储中间结果s2
     * 1.如果当前是数 直接存储到s2 中
     * 2.遇到运算符
     *     1.如果s1中是空 则直接添加到s1中
     *     2.若优先级比s1中的优先级高 直接入栈s1中
     *     3.如果s1栈中优先级高于当前的符号的优先级 直接将s1中的符号pop到s2中。
     * 3.遇到括号
     *     1.如果是左括号 “(” 直接入栈s1
     *     2.如果是右括号 ")" 则依次弹出s1中的符号 知道遇到 ")" 将当前括号消失
     * 4最后将s1中的符号依次弹出 存入到s2中。
     * @param ls
     * @return
     */
    public static List<String> parseSuffixExpreesionList(List<String> ls){
        java.util.Stack<String> s1 = new java.util.Stack();//s1存储符号
        List<String> list = new ArrayList<>();//存储数据

        for (String items:ls) {
            if(items.matches("\\d+")){
                //如果是数字 直接添加到List中
                list.add(items);
            }else if(items.equals("(")){
                //如果是 ( 直接添加到s1中
                s1.push(items);
            }else if(items.equals(")")){
                //如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
                while (!s1.peek().equals("(")){
                    list.add(s1.pop());
                }
                s1.pop();
            }else {
                //当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较
                //问题:我们缺少一个比较优先级高低的方法
                while(s1.size() != 0 && Operation.getValue(items)<=Operation.getValue(s1.peek())){
                    list.add(s1.pop());
                }
                s1.push(items);
            }
        }
        //将s1中的符号依次弹出到s2中
        while (s1.size()!=0){
            list.add(s1.pop());
        }

        return list;
    }

    //获取优先级
    public static class Operation{

        private static final int ADD = 1;
        public static final int SUB = 1;
        public static final int MUL = 2;
        public static final int DIV = 2;


        public static int getValue(String operation){
            int result = 0;
            switch (operation){
                case "+":
                    result = ADD;
                    break;
                case "-":
                    result = SUB;
                    break;
                case "*":
                    result = MUL;
                    break;
                case "/":
                    result = DIV;
                    break;
            }
            return result;
        }


    }

    /***
     * 将中缀表达式存放到list集合中
     * @param str
     * @return
     */
    public  static List<String> toInfixExpressionList(String str){
        List<String> list = new ArrayList<>();
        String strs;
        for (int i = 0; i < str.length(); ) {
            //如果是符号 直接添加
            if(str.charAt(i)<48 || str.charAt(i)>57){
                list.add(str.charAt(i)+"");
                i++;
            }else {
                //如果是数字在依次判断下一个是否是数字
                strs = "";
                while(i<str.length() && str.charAt(i)>=48 && str.charAt(i)<=57){
                    strs+=str.charAt(i);
                    i++;
                }
                list.add(strs);
            }
        }
        return list;
    }

    //将集合中元素 进行运算 [3, 4, +, 5, *, 6, -]
    private static int getExpressionValue(List<String> str){
        java.util.Stack <String>stack = new java.util.Stack();
        for (int i = 0; i < str.size(); i++) {
            String strIndex = str.get(i);
            if(strIndex.matches("\\d+")){//如果是数字 则入栈
                stack.push(strIndex);
            }else {
                //如果是符号 将栈中的最高 和 次高的元素 弹出 进行计算。
                int num = Integer.parseInt(stack.pop());
                int num2 = Integer.parseInt(stack.pop());
                int result = 0;
                if(strIndex.equals("+")){
                    result = num + num2;
                }else if(strIndex.equals("-")){
                    result = num2 - num;
                }else if(strIndex.equals("*")){
                    result = num2 * num;
                }else if(strIndex.equals("/")){
                    result = num2 / num;
                }
                stack.push(result+"");
            }
        }
        return Integer.parseInt(stack.pop());
    }

    //将当前的字符串转换成String 到List集合中
    private static List<String> getStrList(String str){
        List<String> list = new ArrayList<>();
        String [] strs = str.split(" ");
        for(String string : strs){
            list.add(string);
        }
        return list;
    }

}