Résumé des expressions de préfixe, infixe, suffixe et opérations simples


titre : Préfixe, infixe, expression de suffixe et résumé de la mise en œuvre du calcul simple
date : 2023-06-30 10:25:50
tags :

  • Catégories d'expressions
     :
  • Connaissance du développement et autre
    couverture : https://cover.png
    feature : false

1. Conception

1.1 Que sont les expressions préfixe, infixe et postfixe ?

  • Expression de préfixe : également connue sous le nom de notation polonaise , l'opérateur est placé avant les deux opérandes sous forme de préfixe (par exemple : l'expression de préfixe de 3 + 2 est + 3 2)
  • Expression infixe : L'opérateur est situé au milieu de l'opérande sous forme d'infixe (tel que : 3 + 2), qui est notre méthode d'expression commune des formules arithmétiques et logiques dans la vie quotidienne
  • Expression suffixe : également connue sous le nom de Reverse Polish Notation ( RPN ), l'opérateur est placé après les deux opérandes sous forme de suffixe (par exemple : l'expression suffixe de 3 + 2 est 3 2 +)

Les expressions infixes doivent souvent utiliser des parenthèses pour entourer l'opérateur et les opérandes correspondants pour indiquer l'ordre des opérations, comme 5 * (2 + 1) Bien que la priorité de * soit supérieure à +, la présence de parenthèses indique que l'opération + à l'intérieur des parenthèses doit être effectuée en premier. Convient à la structure de pensée humaine et aux habitudes informatiques, mais ne convient pas aux ordinateurs

Contrairement aux expressions infixes, ni les expressions préfixes ni postfixes n'ont besoin d'utiliser des parenthèses pour identifier la priorité des opérateurs, ce qui convient aux ordinateurs. Cependant, le calcul des expressions de suffixe est effectué dans l'ordre dans lequel les opérateurs apparaissent de gauche à droite (indépendamment de la priorité entre les opérateurs), ce qui est plus conforme aux habitudes de lecture humaines.Par conséquent, dans les programmes informatiques réels, les expressions de suffixe sont essentiellement utilisées pour stocker des formules, et les expressions de préfixe sont moins efficaces. Pour les expressions infixées, nous pouvons d'abord les convertir en expressions postfixées, puis les évaluer

1.2 Correspondance arborescente

En fait, les expressions préfixées, les expressions infixes et les expressions postfixées sont trois façons différentes de stocker et de calculer des expressions à travers des arbres, correspondant respectivement au parcours pré-ordre, au parcours dans l'ordre et au parcours post-ordre de l'arbre. Comme indiqué ci-dessous, il s'agit d'un arbre binaire

  • Pour l'arbre ci-dessus, le parcours de préordre est *+a−bcd, ce qui correspond à l'expression de préfixe
  • Le parcours dans l'ordre est a+b−c∗d, mais cette représentation est ambiguë, ce qui signifie que ab est un sous-arbre, cd est un sous-arbre, puis soustrait, donc l'expression infixe doit utiliser des parenthèses pour exprimer correctement le résultat souhaité. L'expression infixe est : (a+(b−c))∗d, et les parenthèses représentent l'ensemble d'un sous-arbre
  • La traversée post-ordre est abc−+d∗, qui est l'expression postfixée correspondante

2. Évaluation des expressions

2.1 Stockage et évaluation d'expressions à travers une structure arborescente

L'idée de mise en œuvre est relativement simple. Si le paramètre est stocké sur le nœud, alors la valeur du paramètre est la valeur du nœud ; si l'opérateur est stocké sur le nœud, le sous-arbre gauche et le sous-arbre droit du nœud sont utilisés pour les opérations correspondantes, et le résultat obtenu est utilisé comme valeur du nœud.

abréviation du code

2.2 Analyse et évaluation des expressions de préfixe

∗ + a − bcd ∗+a−bcd+unbcd _ _

En observant les règles des expressions de préfixe, nous pouvons constater que chaque fois que deux valeurs apparaissent dans une ligne, il doit y avoir un opérateur devant. Ceci est déterminé par les caractéristiques du parcours de préordre (autour de la racine, et la racine est une expression). Par conséquent, nous prenons trois éléments à tour de rôle, jugeons qu'ils remplissent les deux conditions numériques consécutives et effectuons des opérations pour obtenir la valeur d'un nœud d'opérateur. Une récursivité répétée de cette manière peut finalement trouver la valeur de l'expression

abréviation du code

2.3 Analyse et évaluation des expressions postfixées

abc − + d ∗ abc−+d∗ab c+ d

Semblable à l'expression de préfixe, c'est en fait la caractéristique de la traversée post-ordre, c'est-à-dire que tant qu'il y a un opérateur, les deux premiers éléments doivent être des opérandes (racines gauche et droite), puis les trois mêmes éléments sont retirés, et l'opération est jugée remplir les conditions

Voir 3 pour le code détaillé

2.4 Convertir une expression infixe en expression postfixe

( une + ( b - c ) ) ∗ ré (a+(b−c))∗ d( un+( bc ))d

Il est fastidieux d'évaluer directement une expression infixe, nous la convertissons donc en une expression postfixée, puis nous l'évaluons de manière pratique. La difficulté de convertir une expression infixe en expression suffixe est qu'il faut tenir compte de la priorité des parenthèses et des opérateurs. Les étapes sont les suivantes. Cet algorithme de conversion n'est pas généré de toutes pièces, mais est déduit en fonction des caractéristiques de l'expression suffixe

  1. Créez deux piles, S1 est utilisé pour stocker les éléments de sortie et S2 est utilisé pour stocker les opérateurs. Étant donné que les opérateurs de l'expression ont la priorité, ils doivent être temporairement stockés sur la pile
  2. Lire les éléments un par un du haut de la pile d'expressions infixes à la fin de la pile
  3. Si l'opérande est lu, il est directement ajouté à la fin de la pile S1. Parce que les opérandes d'expression postfix viennent toujours avant les opérateurs
  4. Si la parenthèse gauche est lue, elle est directement placée en haut de la pile S2. Parce que la parenthèse ouvrante ne peut pas être traitée avant la parenthèse fermante
  5. Si l'opérateur est lu et que la pile S2 est vide ou si l'élément supérieur de la pile S2 est une parenthèse gauche, il est poussé directement vers le haut de la pile S2. Parce que ce cas ne nécessite pas la priorité de l'opérateur de comparaison
  6. Si un opérateur est lu, et que le haut de la pile S2 est également un opérateur, et que la priorité de l'opérateur actuel est supérieure à l'élément en haut de la pile, alors l'opérateur actuel est poussé vers le haut de la pile S2. Étant donné que l'opérateur lu plus tard peut avoir une priorité plus élevée que l'opérateur actuel, l'opérateur actuel ne peut pas être sorti temporairement
  7. Si un opérateur est lu et que le haut de la pile S2 est également un opérateur, et que la priorité de l'opérateur actuel est inférieure ou égale à l'élément en haut de la pile, placez l'opérateur en haut de la pile S2 et ajoutez-le à la fin de la pile S1. Parce que l'opérateur avec la priorité la plus élevée doit d'abord participer à l'opération. Notez qu'il s'agit d'un processus récursif, car il peut déjà y avoir plusieurs opérateurs dans S2, et leur priorité peut être supérieure ou égale à l'opérateur actuel. Lorsque ces opérateurs apparaissent, l'opérateur actuel sera placé en haut de la pile S2.
  8. Si la parenthèse droite est lue, tous les opérateurs au-dessus de la première parenthèse gauche dans S2 seront ajoutés à la fin de la pile S1. Comme les parenthèses ont la priorité la plus élevée, l'opération est effectuée immédiatement

Exemple : L'expression infixe 2*(3+5)+7/1-4 est convertie en une expression postfixée

Il peut d'abord être converti en arbre, puis l'expression de suffixe est obtenue par parcours post-ordre, puis vérifiée avec le résultat calculé au cours des étapes ci-dessus pour déterminer s'il est correct. Ce qu'il faut souligner dans la conversion, c'est que nous utilisons des parenthèses pour indiquer le calcul de la priorité

Dans l'expression 2*(3+5)+7/1-4, nous convenons que * et / ont une priorité plus élevée que + et -, donc + et - doivent être calculés avec des parenthèses. Mais pour + et - lui-même, * et / ont une priorité élevée, qui est aussi une sorte de calcul de priorité, et des parenthèses doivent être ajoutées pour le calcul de priorité, mais nous avons convenu de calculer * et / en premier au début, et aussi pour plus de commodité, donc les parenthèses sont omises

Y compris * et/ou + et - au même niveau. Nous avons convenu de compter de gauche à droite. En fait, le côté gauche est compté en premier, ce qui est également un calcul de priorité. Nous ajoutons des parenthèses au calcul de priorité, de sorte que la formule d'origine devrait être : ((2*(3+5))+(7/1)) -4

Souligner ce point est principalement pour la commodité de diviser les sous-arbres gauche et droit lors de la conversion en un arbre. Les crochets sont l'ensemble d'un sous-arbre, de sorte que la structure de l'arbre converti est très claire. [Left subtree operator right subtree ]

La traversée post-ordre est : 235+*71/+4-, qui est l'expression postfixée

À ce stade, l'expression de suffixe peut être obtenue en suivant les étapes ci-dessus

On peut voir que le résultat final est également 235+*71/+4-

Voir 3 pour le code détaillé

3. Réalisation d'une opération simple

Classe de calculatrice

public class Calculator {
    
    

    private static final Map<String, Integer> OPERATORS = MapUtil.builder("+", 1).put("-", 1).put("*", 2).put("/", 2)
            .put("%", 2).put("^", 3).put("(", 0).put(")", 0).build();

    private Calculator() {
    
    
    }

    public static double calculate(String equation) {
    
    
        if (!BaseUtil.isWholeSymbol(equation)) {
    
    
            throw new IllegalArgumentException("请确认括号是否完整");
        }

        Deque<String> operand = new ArrayDeque<>();
        Deque<String> operator = new ArrayDeque<>();

        for (String str : toList(equation)) {
    
    
            if (NumberUtils.isCreatable(str)) {
    
    
                operand.push(str);
                continue;
            }

            Integer opt = OPERATORS.get(str);
            if (null == opt) {
    
    
                throw new IllegalArgumentException("操作符不合法");
            }

            if (StrPool.LBRACKET.value().equals(str) || operator.isEmpty() || opt > OPERATORS.get(operator.peek())) {
    
    
                operator.push(str);
            } else if (StrPool.RBRACKET.value().equals(str)) {
    
    
                // 判断是否是右括号, 存在右括号则运算符栈必有左括号, 即运算符栈不为空
                while (!operator.isEmpty()) {
    
    
                    if (StrPool.LBRACKET.value().equals(operator.peek())) {
    
    
                        operator.pop();
                        break;
                    } else {
    
    
                        String calculate = calculate(operator.pop(), operand.pop(), operand.pop());
                        operand.push(calculate);
                    }
                }
            } else if (opt <= OPERATORS.get(operator.peek())) {
    
    
                while (!operator.isEmpty() && opt <= OPERATORS.get(operator.peek())) {
    
    
                    String calculate = calculate(operator.pop(), operand.pop(), operand.pop());
                    operand.push(calculate);
                }
                operator.push(str);
            }
        }

        while (!operator.isEmpty()) {
    
    
            String calculate = calculate(operator.pop(), operand.pop(), operand.pop());
            operand.push(calculate);
        }
        return Double.parseDouble(operand.pop());
    }


    public static List<String> toList(String str) {
    
    
        List<String> list = new ArrayList<>();
        StringBuilder builder = new StringBuilder();

        String replace = str.replaceAll("\\s*", "");
        char[] chars = replace.toCharArray();
        for (int i = 0; i < chars.length; i++) {
    
    
            boolean isMinus = '-' == chars[i] && (i == 0 || '(' == chars[i - 1]);
            if (isMinus) {
    
    
                builder.append(chars[i]);
                continue;
            }

            String val = String.valueOf(chars[i]);
            if (null != OPERATORS.get(val)) {
    
    
                if (StringUtil.INSTANCE.isNotBlank(builder)) {
    
    
                    list.add(builder.toString());
                }
                list.add(val);
                builder = new StringBuilder();
            } else {
    
    
                builder.append(chars[i]);
            }
        }

        if (StringUtil.INSTANCE.isNotBlank(builder)) {
    
    
            list.add(builder.toString());
        }
        return list;
    }

    private static String calculate(String operator, String val2, String val1) {
    
    
        double pre = Double.parseDouble(val1);
        double suf = Double.parseDouble(val2);

        switch (operator) {
    
    
            case "+":
                return pre + suf + "";
            case "-":
                return pre - suf + "";
            case "*":
                return pre * suf + "";
            case "/":
                return pre / suf + "";
            case "%":
                return pre % suf + "";
            case "^":
                return Math.pow(pre, suf) + "";
            default:
                return "0";
        }
    }
}

Classe BaseUtil

public class BaseUtil {
    
    

    private static final Map<Character, Character> R_SYMBOL = MapUtil.builder(')', '(').put(']', '[').put('}', '{').build();

    private static final List<Character> L_SYMBOL = ListUtil.list('(', '[', '{');

    private BaseUtil() {
    
    
    }

    public static boolean isWholeSymbol(String str) {
    
    
        Deque<Character> symbol = new ArrayDeque<>();

        for (char ch : str.toCharArray()) {
    
    
            if (R_SYMBOL.containsKey(ch)) {
    
    
                if (symbol.isEmpty() || !symbol.peek().equals(R_SYMBOL.get(ch))) {
    
    
                    return false;
                }
                symbol.pop();
            } else if (L_SYMBOL.contains(ch)) {
    
    
                symbol.push(ch);
            }
        }

        return symbol.isEmpty();
    }
}

Je suppose que tu aimes

Origine blog.csdn.net/ACE_U_005A/article/details/131769220
conseillé
Classement