Есть ли способ сократить это время?
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
}