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.

60voto

paddy Points 26183

Bien sûr, vous pourriez simplement utiliser une chaîne d'opérateurs valides et la rechercher.

#include <cstring>

// : :

const char* ops = "+-*/";
while(strchr(ops, temp->left->oper) || strchr(ops, temp->right->oper))
{
     // do something
}

Si vous êtes préoccupé par les performances, alors peut-être que les consultations de table :

#include <climits>

// : :

// Start with a table initialized to all zeroes.
char is_op[1 << CHAR_BIT] = {0};

// Build the table any way you please.  This way using a string is handy.
const char* ops = "+-*/";
for (const char* op = ops; *op; op++) is_op[*op] = 1;

// Then tests require no searching
while(is_op[temp->left->oper] || is_op[temp->right->oper])
{
     // do something
}

15 votes

Il faut être un peu plus prudent avec strchr parce que (c'est un fait peu connu) que ce sera également vrai si l'un ou l'autre des deux éléments suivants temp->left->oper o temp->right->oper est égal à '\0' . Mais en pratique, c'est probablement une bonne solution.

0 votes

Oui, j'ai exploité cette fonctionnalité dans le passé. Dans tous les cas, j'ai ajouté une alternative avec une table de consultation... pour la rapidité :)

3 votes

Vous souhaitez probablement extraire l'implémentation dans une fonction séparée.

38voto

JeJo Points 12135

Oui, en effet, vous le pouvez !

Stocker les caractères valides dans un fichier std::array ou même un tableau simple et appliquer l'algorithme standard std::any_of pour vérifier la condition.

#include <array>     // std::array
#include <algorithm> // std::any_of

static constexpr std::array<char, 4> options{ '+', '-', '*', '/' };
const auto tester = [temp](const char c) { return temp->left->oper == c || temp->right->oper == c; };
const bool isValid = std::any_of(options.cbegin(), options.cend(), tester);

while(isValid) // now the while-loop is simplified to
{
    // do something
}

Cela peut être plus propre en l'emballant dans une fonction, qui accepte l'élément node l'objet à vérifier.

#include <array>     // std::array
#include <algorithm> // std::any_of

bool isValid(const node *const temp) /* noexcept */
{
   static constexpr std::array<char, 4> options{ '+', '-', '*', '/' };
   const auto tester = [temp](const char c) { return temp->left->oper == c || temp->right->oper == c; };
   return std::any_of(options.cbegin(), options.cend(), tester);
}

qui peut être appelé dans le while-loop

while (isValid(temp)) // pass the `node*` to be checked
{
    // do something
}

31voto

Jarod42 Points 15729

Créez une sous-fonction,

bool is_arithmetic_char(char)
{
// Your implementation or one proposed in another answers.
}

et ensuite :

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

1 votes

A titre d'information, une telle fonction pourrait également être ajoutée à node ou une partie d'une classe qui hérite de node sans ajouter de nouveaux membres de données, sans rompre son caractère standard.

2 votes

Je ne suis jamais convaincu par ce genre de "micro-refactorisation". Tout ce que ça fait, c'est déplacer les bugs dans le code d'un endroit où vous pouvez les voir dans le contexte dans lequel ils sont utilisés, à un endroit où tu ne peux pas. Bien sûr, si le même test se produit à d'autres endroits de l'application, c'est une bonne raison pour en tenir compte.

2 votes

@alephzero Je préférerais ce genre de sous-fonction dans ce cas car (1) ils abstraient une définition qui peut changer si vous voulez ajouter des opérateurs plus tard (2) ils fournissent une petite interface testable (3) ils peuvent être documentés dans le fichier d'en-tête.

14voto

MCCCS Points 389

Le style C :

int cont = 1;
while(cont)
    switch(temp->left->oper) {
    case '+':
    case '-':
    ...
    case '/':
        // Do something
        break;
    default:
        cont = 0;
    }

Vous devrez peut-être joindre // Do something avec des accolades si vous voulez déclarer des variables.

8 votes

Ce n'est pas seulement du "style C". Il y a de très bonnes raisons de préférer faire cela pour cette situation exacte, car le compilateur est capable de construire un fichier table de saut beaucoup plus efficacement qu'un ensemble de données (théoriquement) sans rapport entre elles. if des contrôles. Même s'il ne peut pas le faire, "je compare un tas de constantes différentes à la même variable" est une bonne information à donner au compilateur qui peut l'aider à optimiser beaucoup mieux.

3 votes

Il serait encore mieux de changer la condition en while (1) ; changer le premier break a continue ; modifier le default cas à break ; et ajouter une autre rupture après le switch . J'ai utilisé ce modèle à de nombreuses reprises chez les interprètes.

0 votes

@T.E.D. Je suis sceptique quant à votre prémisse. Un cas switch avec un tas de cas en cascade n'est pas différent des instructions if avec des conditions disjonctives (OU ensemble). Les humains peuvent ne pas reconnaître cela visuellement, mais je serais surpris que les compilateurs ne supportent pas les deux de manière égale.

6voto

L. F. Points 11270

Vous pouvez construire une chaîne qui contient les options et rechercher le caractère :

#include <string>

// ...

for (auto ops = "+-*/"s; ops.find(temp-> left->oper) != std::string::npos ||
                         ops.find(temp->right->oper) != std::string::npos;)
    /* ... */;

El "+-*/"s est une fonctionnalité du C++14. Utilisez std::string ops = "+-*/"; avant C++14.

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