web-dev-qa-db-fra.com

Supprimer les parenthèses redondantes d'une expression arithmétique

C'est une question d'entrevue pour laquelle je n'ai trouvé aucune réponse satisfaisante sur stackoverflow ou à l'extérieur. Déclaration du problème: 

Étant donné une expression arithmétique, supprimez les parenthèses redondantes. Par exemple. ((a * b) + c) devrait devenir a * b + c

Je peux penser à un moyen évident de convertir l’expression infixe en post-correctif et de le reconvertir en infixe - mais existe-t-il un meilleur moyen de le faire?

11
Darth.Vader

Une paire de parenthèses est nécessaire si et seulement si elles englobent une expression non entre-exprimée de la forme X% X% ...% X où X sont des expressions ou des atomes entre parenthèses, et% sont des opérateurs binaires, et si au moins un des opérateurs % a une priorité inférieure à celle d'un opérateur attaché directement à l'expression entre parenthèses de part et d'autre de celle-ci; ou si c'est l'expression entière. Donc, par exemple dans

q * (a * b * c * d) + c

les opérateurs environnants sont {+, *} et l'opérateur de priorité le plus bas à l'intérieur des parenthèses est *, les parenthèses sont donc inutiles. D'autre part, dans

q * (a * b + c * d) + c

il y a un opérateur de priorité plus faible + entre les parenthèses que l'opérateur * environnant, ils sont donc nécessaires. Cependant, dans

z * q + (a * b + c * d) + c

les parenthèses ne sont pas nécessaires car * extérieur n'est pas attaché à l'expression entre parenthèses.

Pourquoi est-ce vrai que si tous les opérateurs d'une expression (X% X% ...% X) ont une priorité supérieure à celle d'un opérateur environnant, les opérateurs internes sont toujours calculés en premier, même si les parenthèses sont supprimées.

Ainsi, vous pouvez vérifier la redondance de toute paire de parenthèses correspondantes directement avec cet algorithme:

Let L be operator immediately left of the left parenthesis, or nil
Let R be operator immediately right of the right parenthesis, or nil
If L is nil and R is nil:
  Redundant
Else:
  Scan the unparenthesized operators between the parentheses
  Let X be the lowest priority operator
  If X has lower priority than L or R:
    Not redundant
  Else:
    Redundant

Vous pouvez effectuer une itération en supprimant les paires redondantes jusqu'à ce que toutes les paires restantes ne soient plus redondantes.

Exemple:

((a * b) + c * (e + f))

(Traitement des paires de gauche à droite):

((a * b) + c * (e + f))   L = nil R = nil --> Redundant
^                     ^   
 (a * b) + c * (e + f)    L = nil R = nil --> Redundant
 ^     ^                  L = nil R = + X = * --> Redundant
  a * b  + c * (e + f)    L = * R = nil X = + --> Not redundant
               ^     ^

Résultat final:

a * b + c * (e + f)
33
Antti Huima

Je viens de trouver une réponse:

les locaux sont:

1. the expression has been tokenized
2. no syntax error
3. there are only binary operators

contribution: 

list of the tokens, for example:
   (, (, a, *, b, ), +, c, )

sortie:

set of the redundant parentheses pairs (the orders of the pairs are not important),
for example,
   0, 8
   1, 5

veuillez noter que: l'ensemble n'est pas unique, par exemple, ((a + b)) * c, nous pouvons supprimer les parenthèses externes ou internes, mais l'expression finale est unique 

la structure de données:

a stack, each item records information in each parenthese pair
the struct is:
   left_pa: records the position of the left parenthese
   min_op: records the operator in the parentheses with minimum priority
   left_op: records current operator

l'algorithme

1.Push one empty item in the stack
2.scan the token list
    2.1 if the token is operand, ignore
    2.2 if the token is operator, records the operator in the left_op, 
        if min_op is nil, set the min_op = this operator, if the min_op 
        is not nil, compare the min_op with this operator, set min_op as 
        one of the two operators with less priority
    2.3 if the token is left parenthese, Push one item in the stack, 
        with left_pa = position of the parenthese
    2.4 if the token is right parenthese, 
        2.4.1 we have the pair of the parentheses(left_pa and the 
             right parenthese)
        2.4.2 pop the item
        2.4.3 pre-read next token, if it is an operator, set it 
             as right operator
        2.4.4 compare min_op of the item with left_op and right operator
             (if any of them exists), we can easily get to know if the pair 
             of the parentheses is redundant, and output it(if the min_op
             < any of left_op and right operator, the parentheses are necessary,
             if min_op = left_op, the parentheses are necessary, otherwise
             redundant) 
        2.4.5 if there is no left_op and no right operator(which also means 
             min_op = nil) and the stack is not empty, set the min_op of top 
             item as the min_op of the popped-up item

exemples

exemple un

((a*b)+c)

après avoir numérisé en b, nous avons pile:

index left_pa min_op left_op
0
1     0       
2     1       *      *       <-stack top

à présent, nous rencontrons le premier ')' (à la pos 5), nous ouvrons l'élément 

left_pa = 1 
min_op = *
left_op = *

et opérateur de pré-lecture '+', étant donné que min_op priority '*'> '+', le couple (1,5) est redondant, alors exportez-le. puis numérisez jusqu'à la dernière réunion ')', pour le moment, nous avons pile

index left_pa min_op left_op
0
1     0       +      + 

nous affichons cet élément (puisque nous rencontrons ')' à la pos 8) et pré-lisons l'opérateur suivant, puisqu'il n'y a pas d'opérateur et qu'à l'index 0, il n'y a pas de left_op, donc la paire (0, 8) 

exemple deux

a*(b+c)

quand on rencontre le ')', la pile est comme:

index  left_pa  min_op left_op
0               *      *
1      2        +      +

maintenant, nous ouvrons l'élément à l'index = 1, comparons le min_op '+' avec le left_op '*' à l'index 0, nous pouvons découvrir que les '(', ')' sont nécessaires

2
lucian
  1. Poussez un élément vide dans la pile
  2. Analyser la liste de jetons

    2.1 si le jeton est un opérande, ignorez.

    2.2 si le jeton est opérateur, enregistre l'opérateur dans le left_op, Si min_op est nul, définissez l'opérateur min_op = this, si min_op N'est pas nul, comparez min_op à cet opérateur, définissez min_op comme l'un des deux opérateurs moins prioritaires.

    2.3 si le jeton est laissé entre parenthèses, Placer un élément de la pile, Avec left_pa = position de la parenthèse.

    2.4 si le jeton est la parenthèse correcte:

    2.4.1 nous avons la paire des parenthèses (left_pa et la Parenthèse droite)

    2.4.2 pop l'élément

    2.4.3 pré-lire le jeton suivant, s'il s'agit d'un opérateur, définissez-le Comme opérateur de droite

    2.4.4 comparer min_op de l'item avec left_op et l'opérateur droit (S'il en existe un), nous pouvons facilement savoir si la paire Des parenthèses est redondante et la sortir ( si min_op <tout opérateur left_op et right, les parenthèses sont nécessaires, si min_op = left_op, les parenthèses sont nécessaires, sinon redondant) 

    2.4.5 s'il n'y a pas d'opérateur left_op ni d'opérateur right (ce qui signifie également Min_op = nil) et que la pile n'est pas vide, définissez l'élément min_op de top Comme élément min_op de la fonction popped up item exemples

1
xyz1

Cette solution fonctionne si l'expression est valide. Nous avons besoin de mapper les opérateurs sur les valeurs prioritaires.

une. Parcourez les deux extrémités du tableau pour déterminer la parenthèse correspondante des deux extrémités. Soit les indices i et j respectivement.

b. Parcourez maintenant de i à j et trouvez l'opérateur de priorité le plus bas qui ne figure dans aucune parenthèse.

c. Comparez la priorité de cet opérateur avec les opérateurs situés à gauche de la parenthèse ouverte et à droite de la parenthèse de fermeture. Si aucun tel opérateur n'existe, traitez sa priorité comme -1. Si la priorité de l'opérateur est supérieure à ces deux, supprimez la parenthèse en i et j.

ré. Continuez les étapes a à c jusqu'à ce que i <= j.

0
Raj

Le code ci-dessous est une solution simple, limitée à +-*/; si vous le souhaitez, vous pouvez les ajouter selon vos besoins.

#include <iostream>
#include <stack>
#include <set>
using namespace std;

int size;
int loc;
set<char> support;
string parser(string input , int _loc){

    string expi;
    set<char> op;
    loc = _loc;

    while(1){
        if(input[loc] ==  '('){
            expi += parser(input,loc+1);
        }else if(input[loc] == ')'){
          if((input[loc+1] != '*') && (input[loc+1] != '/')){
              return expi;
          }else{
              if ((op.find('+') == op.end()) && (op.find('-') == op.end())){
                  return expi;
              }else{
                  return '('+expi+')';
              }
          }
        }else{
            char temp = input[loc];
            expi=expi+temp;
            if(support.find(temp) != support.end()){
                op.insert(temp);
            }
        }
        loc++;
        if(loc >= size){
            break;
        }
    }

    return expi;
}

int main(){
    support.insert('+');
    support.insert('-');
    support.insert('*');
    support.insert('/');

    string input("(((a)+((b*c)))+(d*(f*g)))");
    //cin >> input;
    size = input.size();

    cout<<parser(input,0);

    return 0;
}       
0
nagu