53 votes

Existe-t-il un moyen de raccourcir cette condition ?

while (temp->left->oper == '+' || 
       temp->left->oper == '-' || 
       temp->left->oper == '*' || 
       temp->left->oper == '/' || 
       temp->right->oper == '+' || 
       temp->right->oper == '-' || 
       temp->right->oper == '*' || 
       temp->right->oper == '/')
{
    // do something
}

Pour plus de clarté : temp est un pointeur qui pointe vers le suivant node structure :

struct node
{
    int num;
    char oper;
    node* left;
    node* right;
};

1 votes

Sans connaître les dépendances entre temp->left y temp->right vous ne pouvez pas optimiser dans tous les opérateurs égaux. Optiquement, vous pourriez utiliser des expressions régulières, mais en interne, c'est probablement à peu près la même chose, voire moins efficace.

3 votes

Je serais intéressé de savoir pourquoi vous pensez avoir ce problème. Cela ressemble à l'interprétation d'un arbre d'expression au moment de l'exécution, et si c'est le cas, il existe de bien meilleures façons de le faire.

5voto

Quuxplusone Points 4320

La programmation est le processus qui consiste à trouver les redondances et à les éliminer.

struct node {
    int num;
    char oper;
    node* left;
    node* right;
};

while (temp->left->oper == '+' || 
       temp->left->oper == '-' || 
       temp->left->oper == '*' || 
       temp->left->oper == '/' || 
       temp->right->oper == '+' || 
       temp->right->oper == '-' || 
       temp->right->oper == '*' || 
       temp->right->oper == '/') {
    // do something
}

Quelle est l'"unité répétée" ici ? Eh bien, je vois deux instances de

   (something)->oper == '+' || 
   (something)->oper == '-' || 
   (something)->oper == '*' || 
   (something)->oper == '/'

Nous allons donc factoriser cette partie répétée dans une fonction, afin de ne l'écrire qu'une seule fois.

struct node {
    int num;
    char oper;
    node* left;
    node* right;

    bool oper_is_arithmetic() const {
        return this->oper == '+' || 
               this->oper == '-' || 
               this->oper == '*' || 
               this->oper == '/';
    }
};

while (temp->left->oper_is_arithmetic() ||
       temp->right->oper_is_arithmetic()) {
    // do something
}

Ta-da ! Raccourci !
(Code original : 17 lignes, dont 8 sont la condition de la boucle. Code révisé : 18 lignes, dont 2 sont la condition de la boucle).

3voto

user3281036 Points 105

"+" "-" "*" et "/" sont des valeurs décimales ASCII 42, 43, 45 et 47 donc

#define IS_OPER(x) (x > 41 && x < 48 && x != 44 && x != 46)

while(IS_OPER(temp->left->oper || IS_OPER(temp->right->oper){ /* do something */ }

3voto

kmiklas Points 431

Regex à la rescousse !

#include <regex>

while (
    std::regex_match(temp->left->oper, std::regex("[\+\-\*\/]")) ||
    std::regex_match(temp->right->oper, std::regex("[\+\-\*\/]"))
) { 
// do something
}

EXPLICATION : Les crochets de regex [] indiquent une "classe de caractères" de regex. Cela signifie "correspondre à tout caractère listé à l'intérieur des crochets". Par exemple, g[eiou]t correspondrait à "get", "git", "got" et "gut", mais PAS à "gat". Les barres obliques inversées sont nécessaires car le plus (+), le moins (-), l'étoile (*) et la barre oblique (/) ont une signification dans une classe de caractères.

AVERTISSEMENT : Je n'ai pas le temps d'exécuter ce code ; vous devrez peut-être le modifier, mais vous comprenez l'idée. Vous devrez peut-être déclarer/convertir oper d'un char à un std::string .

RÉFÉRENCES
1. http://www.cplusplus.com/reference/regex/regex_match/
2. https://www.rexegg.com/regex-quickstart.html
3. https://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/0596528124/ref=sr_1_1?keywords=regex&qid=1563904113&s=gateway&sr=8-1

3voto

U. Windl Points 453

En échangeant l'espace contre le temps, vous pourriez construire deux tableaux "booléens" indexés par temp->left->oper y temp->left->oper respectivement. Le tableau correspondant contient vrai lorsque la condition est remplie, faux autrement. Donc :

while (array1[temp->left->oper] || array1[temp->right->oper]) {
// do something
}

Comme les ensembles pour la gauche et la droite semblent identiques, un fera réellement.

L'initialisation se ferait comme suit :

static char array1[256]; // initialized to "all false"

...

array1['+'] = array1['-'] = array1['*'] = array1['/'] = '\001';

Similaire pour array2 . Comme les sauts sont mauvais pour les CPU modernes à pipelining, vous pourriez même utiliser une table plus grande comme celle-ci :

while (array1[temp->left->oper << 8 | temp->right->oper]) {
    // do something
}

Mais l'initialisation est plus délicate :

static char array1[256 * 256]; // initialized to "all false"

...

void init(char c) {
    for (unsigned char i = 0; i <= 255; ++i) {
        array1[(c << 8) | i] = array1[(i << 8) | c] = '\001';
    }
}

init('+');
init('-');
init('*');
init('/');

2voto

Spartan Points 41

Mettre les opérateurs dans le unordered_set sera beaucoup plus efficace et fournira un accès O(1) aux opérateurs.

unordered_set<char> u_set;                                                                                                                                                   
u_set.insert('+');                                                                                                                                                           
u_set.insert('*');                                                                                                                                                           
u_set.insert('/');                                                                                                                                                           
u_set.insert('-');                                                                                                                                                           

if((u_set.find(temp->left->oper) != u_set.end()) || (u_set.find(temp->right->oper) != u_set.end())) {     
                 //do something                                                                                                                
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X