Есть ли способ сократить это время?

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
}

Для ясности: temp - указатель, который указывает на эту структуру:

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

Ответы

Ответ 1

Конечно, вы можете просто использовать строку допустимых операторов и искать ее.

#include <cstring>

// : :

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

Если вас беспокоит производительность, то, возможно, поиск по таблице:

#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
}

Ответ 2

Да, действительно, вы можете!

Сохраните действительные символы в std::array или даже в простом массиве и примените к нему стандартный алгоритм std::any_of для проверки условия.

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

const std::array<char, 4> options{ '+', '-', '*', '/' };
const auto tester = [&temp](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
}

Это может быть более очищено упаковкой в функцию, которая принимает проверяемый объект node.

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

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

который можно вызвать в while-loop

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

Ответ 3

Создать подфункцию,

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

а потом:

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

Ответ 4

C-стиль:

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

Вам может понадобиться заключить //Do something с помощью фигурных скобок, если вы собираетесь объявлять переменные.

Ответ 5

Вы можете создать строку, содержащую параметры и найти символ:

#include <string>

// ...

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

"+-*/"s - это функция С++ 14. Используйте std::string ops = "+-*/"; до С++ 14.

Ответ 6

Программирование - это процесс поиска избыточностей и их устранения.

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
}

Что за "повторяющаяся единица" здесь? Ну, я вижу два случая

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

Так что пусть фактор, который повторяется, входит в функцию, так что нам нужно написать ее только один раз.

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
}

Та-да! Укороченный!
(Исходный код: 17 строк, 8 из которых являются условиями цикла. Пересмотренный код: 18 строк, 2 из которых являются условиями цикла.)

Ответ 7

"+" "-" "*" и "/" являются десятичными значениями ASCII 42, 43, 45 и 47, таким образом

#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 */ }

Ответ 8

Regex на помощь!

#include <regex>

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

ОБЪЯСНЕНИЕ: квадратные скобки [] обозначают регулярное выражение "класс символов". Это означает "соответствовать любому символу, указанному в скобках". Например, g[eiou]t будет соответствовать "get", "git", "got" и "gut", но НЕ "gat". Обратная косая черта необходима, потому что плюс (+) минус (-) и звездочка (*) и косая черта (/) имеют значение в классе символов.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: У меня нет времени, чтобы запустить этот код; Возможно, вам придется настроить его, но вы поняли идею. Возможно, вам придется объявить/преобразовать oper из char в std::string.

Лит
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

Ответ 9

Торгуя пространством со временем, вы можете построить два "логических" массива, индексированных с помощью temp->left->oper и temp->left->oper соответственно. Соответствующий массив содержит true, когда условие выполнено, иначе false. Так:

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

Поскольку наборы для левого и правого каналов кажутся идентичными, один массив на самом деле подойдет.

Инициализация будет выглядеть так:

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

...

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

Аналогично для array2. Поскольку переходы плохо подходят для современных конвейерных процессоров, вы можете даже использовать таблицу большего размера, например:

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

Но инициализация более сложная:

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('/');

Ответ 10

Помещение операторов в unordered_set будет очень эффективным и обеспечит O (1) доступ к операторам.

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                                                                                                                
}