La pila de estructuras de datos: las potentes cuatro calculadoras de cálculo complejas (comparables a las calculadoras científicas que vienen con Windows) [infijo a expresión de sufijo]

¡Cuatro calculadoras de cálculo complejas que son más fuertes que las calculadoras integradas para Windows!

La medición real jugó aleatoriamente dos conjuntos de fórmulas complejas: -7.5 * 6 / (-2 + (-6.5--5.22)) y 7.5 + -3 * 8 / (7 + 2)

Los resultados de cálculo de la calculadora científica de Windows son: -3.28 (error) y 9 (error), ¡todo está mal! ! ! Los amigos incrédulos pueden contar.

Las respuestas correctas son: 13.71951219512195 y 4.833333333333334

Calculadora que convierte las expresiones de infijo en expresiones de sufijo y realiza cálculos (admite sumas, restas, multiplicaciones y divisiones con signos negativos, paréntesis y decimales)

Paso a paso

Supongamos que existe una fórmula de este tipo: -7.5 * 6 / (-2 + (-6.5--5.22))

Primero debemos analizar esta cadena, que son números y símbolos. (Por ejemplo: -7.5 es un número)

El código específico es el siguiente:


// Expresión a la expresión infija (admite punto decimal, número negativo, paréntesis)
     lista pública <String> getList (expresión de cadena) { 
        List <String> exp = new ArrayList <String> (); // almacena el analizado Expresión infija 
        String merge = "" ;
         int index = 0 ;
         char ch, ch1 = 0 ;
         boolean flag = false ; 
        expression = expression.replace ("", "" );
         while (index! = Expression.length ()) { 
            ch = expresión.substring (índice, índice + 1) .charAt (0 );
            Go+ = ch;
            if (index <expression.length () - 1) { // 防止 下 标 越界 
                ch1 = expression.substring (index + 1, index + 2) .charAt (0 );
                if (isOper (ch1)) { 
                    exp.add (fusionar); 
                    fusionar = "" ; 
                    bandera = falso ; 
                } else  if (isOper (ch)) {
                     if (flag == false && exp.size ()> 0 ) { 
                        exp.add (fusionar); 
                        fusionar = "" ;
                        bandera = falso ; 
                    } 
                } 
                if (ch == '(' && ch1 == '-' || isOper (ch) && ch1 == '-' ) 
                    flag = true ; 
            } 
            index ++ ; 
        } 
        exp.add (merge); 
        return exp ; 
    }

El siguiente paso es lo más destacado! ! ! Expresión de infijo—> Diagrama de análisis de expresión de sufijo:


 

 

 

 

 

 

 Siga la regla de la letra roja anterior para tratar el elemento después del segundo paréntesis izquierdo "(" hasta el paréntesis derecho ")"


 

 

 

Agregue todos los símbolos en la pila de símbolos a la lista de la colección hasta que encuentren un corchete izquierdo que coincida con el corchete derecho


 

 

¡Lo anterior es la ilustración de la conversión de expresión infija a expresión sufijo! Obtener: La expresión de sufijo es: 7.5-6 * 2-6.5-5.22 - + /  

El siguiente es un código detallado:


 // Expresión de infijo a expresión de sufijo (hay una variable global menos que registra el índice negativo para un cálculo fácil) 
    public List <String> toRPN (String expression) { 
        List <String> list = getList (expression); 
        List <String > rPN = new ArrayList <String> (); // usado para almacenar la expresión de sufijo 
        Stack <String> exp = new Stack <String> (); // usado para juzgar el símbolo de operación 
        minus = new ArrayList <> ();
         para (Cadena s: lista) { // Iterar a través de cada lista de elementos de expresión infija 
            if (isOper (s)) { // Si la cadena es + - * / 
                if (exp.isEmpty ()) // Si la pila es Vacío, luego solo empuje la pila
                    exp.push (s); // -7.5 * 6 / (-2 + (-6.5- -5.22)) 
                más  si (prioridad (s) <= prioridad (exp.peek ())) { // si está dentro de la pila Hay operadores, luego compare la prioridad con la parte superior del operador de pila 
                    rPN.add (exp.pop ()); // La prioridad actual del operador es menor que la parte superior del operador de pila, luego coloque la parte superior del operador de pila en la expresión de sufijo rPN list 
                    exp.push (s); // Luego presione el operador actual 
                } else 
                    exp.push (s); 

            } else  if (s.equals (")")) { // si la cadena actual es ') 'Luego agregue la cadena en la parte superior de la pila a List rPN hasta que la cadena en la parte superior de la pila sea "(" 
                while (! Exp.peek (). Equals ("(" )) { 
                    rPN.add (exp.pop () );
                } 
                exp.pop (); // Debe recordar abrir el paréntesis izquierdo (emergente, que representa un par de paréntesis pequeños para completar el cálculo 
            ) sino  if (s.equals ("(" )) 
                exp.push (s); // Si es El paréntesis izquierdo se coloca directamente en la pila 
            sino { // de lo contrario es un número, se une directamente a rPN 
                if (s.charAt (0) == '-' ) { 
                    rPN.add (s.substring ( 1 , s.length ())) ; 
                    rPN.add ( "" + s.charAt (0 )); 
                    minus.add (rPN.size () -1); // Variable global menos colección de lista de índice de índice negativo 
                } más
                    rPN.add (s); 
            }
        } 
        while (! exp.isEmpty ()) { // Finalmente, después de escanear la lista, agregue las cadenas en la pila exp a la lista de expresiones de sufijo rPN en la 
            secuencia rPN.add (exp.pop ()); 
        } 
        return rPN; 
    }

 

Un diagrama de análisis para calcular la expresión de sufijo:

 

A continuación, se procesan los símbolos aritméticos:

 

 

 Repita las acciones anteriores hasta que la expresión de sufijo List esté vacía, es decir:

 

 

 


 

Código de cálculo de expresión de sufijo:


// 后缀表达式list进行计算
    public double calcRPN(List<String> rPN) {
        Stack<Double> numStack=new Stack<Double>();
        boolean flag=false;//用来标记是否处理过负号
        for (int i=0; i < rPN.size(); i++) {
            if (isOper( rPN.get( i ) )) {
                if (rPN.get( i ).equals( "-" )) {//这里判断两次,是为了提高查找负号索引位置的效率
                    for (int j=0; j < minus.size(); j++) {//遍历后缀表达式集合中记录的负号的索引下标
                        if (i == minus.get( j )) {//如果rPN后缀表达式的下标等于minus集合中记录的负号索引下标
                            String min=rPN.get( i );//说明此位置的‘-’号,为负号而不是减号
                            Double num=numStack.pop();//那么就pop出数栈,和-拼接
                            numStack.push( Double.parseDouble( min + num ) );
                            flag=true;
                            continue;
                        }
                    }
                    if (flag) {
                        flag=false;
                        continue;
                    }
                }//下面就是常规计算,一定要思量上面两个continue的作用
                double num1=numStack.pop();
                double num2=numStack.pop();
                numStack.push( calc( num1, num2, rPN.get( i ).charAt( 0 ) ) );
            } else {//如果是数字就直接丢到数栈
                numStack.push( Double.valueOf( rPN.get( i ) ) );
            }
        }
        return numStack.pop();
    }

 

 接下来是完成源代码:


public class ReversePolishNotationCalcDemo {
    List<Integer> minus;//用于记录符号出现的索引

    public static void main(String[] args) {
        String expression="-7.5*6/(-2+(-6.5- -5.22))";// 7.5 - 6.5 5.22 - - *
        expression="7.5+-3*8/(7+2)";
        ReversePolishNotationCalcDemo rpn=new ReversePolishNotationCalcDemo();
        System.out.print( "中缀表达式为:" );

        rpn.getList( expression ).forEach( System.out::print );

//        for (String s : rpn.getList(expression)) {
//            System.out.printf("%s  ", s);
//        }
        System.out.println();
        System.out.print( "后缀表达式为:" );
        for (String s : rpn.toRPN( expression )) {
            System.out.printf( "%s  ", s );
        }
        System.out.println();
        double result=rpn.calcRPN( rpn.toRPN( expression ) );
        System.out.println( expression.replace( " ", "" ) + " = " + result );
    }

    // 后缀表达式list进行计算
    public double calcRPN(List<String> rPN) {
        Stack<Double> numStack=new Stack<Double>();
        boolean flag=false;
        for (int i=0; i < rPN.size(); i++) {
            if (isOper( rPN.get( i ) )) {
                if (rPN.get( i ).equals( "-" )) {
                    for (int j=0; j < minus.size(); j++) {
                        if (i == minus.get( j )) {
                            String min=rPN.get( i );
                            Double num=numStack.pop();
                            numStack.push( Double.parseDouble( min + num ) );
                            flag=true;
                            continue;
                        }
                    }
                    if (flag) {
                        flag=false;
                        continue;
                    }
                }
                double num1=numStack.pop();
                double num2=numStack.pop();
                numStack.push( calc( num1, num2, rPN.get( i ).charAt( 0 ) ) );
            } else {
                numStack.push( Double.valueOf( rPN.get( i ) ) );
            }
        }
        return numStack.pop();
    }

    // 中缀表达式转后缀表达式
    public List<String> toRPN(String expression) {
        List<String> list=getList( expression );
        List<String> rPN=new ArrayList<String>();// 用于存放后缀表达式
        Stack<String> exp=new Stack<String>();// 用于操作判断符号
        minus=new ArrayList<>();
        for (String s : list) {// 将中缀表达式每个元素list遍历
            if (isOper( s )) {// 如果字符串是+-*/
                if (exp.isEmpty())// 如果栈是空,那么就直接入栈
                    exp.push( s );//-7.5*6/(-2+(-6.5- -5.22))
                else if (priority( s ) <= priority( exp.peek() )) {// 如果栈里面有运算符,那么就和栈顶运算符比较优先级
                    rPN.add( exp.pop() );// 当前运算符优先级小于栈顶运算符,就把栈顶运算符弹出加入到后缀表达式rPN列表中
                    exp.push( s );// 然后压入当前运算符
                } else
                    exp.push( s );

            } else if (s.equals( ")" )) {// 如果当前字符串是‘)’那么就将栈顶字符串加入add到List rPN中,直到栈顶字符串为"("
                while (!exp.peek().equals( "(" )) {
                    rPN.add( exp.pop() );
                }
                exp.pop();// 一定要记得将左括号(弹出去,代表一对小括号完成计算
            } else if (s.equals( "(" ))
                exp.push( s );// 如果是左括号就直接入栈
            else {// 否则就是数字,直接加入rPN中
                if (s.charAt( 0 ) == '-') {
                    rPN.add( s.substring( 1, s.length() ) );
                    rPN.add( "" + s.charAt( 0 ) );
                    minus.add( rPN.size() - 1 );
                } else
                    rPN.add( s );
            }
        }
        while (!exp.isEmpty()) {// 最后扫描完list后,将栈exp中的字符串依次加入到rPN后缀表达式列表中
            rPN.add( exp.pop() );
        }
        System.out.println( "负号出现的索引:" + Arrays.toString( minus.toArray() ) );
        return rPN;
    }


    // 表达式转中缀表达式(支持小数点,负数,小括号)
    public List<String> getList(String expression) {
        List<String> exp=new ArrayList<String>();
        String merge="";
        int index=0;
        char ch, ch1=0;
        boolean flag=false;
        expression=expression.replace( " ", "" );
        while (index != expression.length()) {
            ch=expression.substring( index, index + 1 ).charAt( 0 );
            merge+=ch;
            if (index < expression.length() - 1) {// 防止下标越界
                ch1=expression.substring( index + 1, index + 2 ).charAt( 0 );
                if (isOper( ch1 )) {
                    exp.add( merge );
                    merge="";
                    flag=false;
                } else if (isOper( ch )) {
                    if (flag == false && exp.size() > 0) {//-7.5*6/(-2+(-6.5- -5.22))
                        exp.add( merge );
                        merge="";
                        flag=false;
                    }
                }
                if (ch == '(' && ch1 == '-' || isOper( ch ) && ch1 == '-')
                    flag=true;
            }
            index++;
        }
        exp.add( merge );
        return exp;
    }

    public boolean isOper(String oper) {
        return oper.equals( "+" ) || oper.equals( "-" ) || oper.equals( "*" ) || oper.equals( "/" );
    }

    public boolean isOper(char oper) {
        return oper == '+' || oper == '-' || oper == '*' || oper == '/' || oper == '(' || oper == ')';
    }

    public int priority(String s) {
        if (s.equals( "+" ) || s.equals( "-" ))
            return 0;
        if (s.equals( "*" ) || s.equals( "/" ))
            return 1;
        return -1;
    }

    public double calc(double num1, double num2, int oper) {
        switch (oper) {
            case '+':
                return num1 + num2;
            case '-':
                return num2 - num1;
            case '*':
                return num1 * num2;
            case '/':
                return num2 / num1;
            default:
                break;
        }
        return 0;
    }
}
完整源代码

Supongo que te gusta

Origin www.cnblogs.com/taichiman/p/12729530.html
Recomendado
Clasificación