Еще один способ решения арифметических выражений в C++?
ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: ЕСЛИ ЭТО СЛИШКОМ ДОЛГО ЧИТАТЬ, ТО ЕСТЬ МОДЕЛЬ TL;DR НА ДНО.
Привет и привет тому, кто это читает. Недавно у меня было собеседование на работу, где они заставили меня сделать домашнее задание по кодированию, которое состояло в том, чтобы напишите программу, которая решает арифметические выражения с использованием C++ объектно-ориентированным способом, не использующим алгоритм маневрового двора Таким образом, я смог написать программу, и я был накачан, когда я понял это, моя программа решала такие проблемы, как (-100.5+2+1+(250/40+4)+100)-10 = 2.75. К сожалению, им это не понравилось, и они решили преследовать других кандидатов, которые сначала были похожи на "F******K", но потом я был похож на то, что все это хорошо. Однако мне действительно любопытно посмотреть, что они искали. Какой другой подход я мог бы выбрать? Вот фрагмент, который показывает, что я сделал:
В Скобках:
// Private helper method for computing values in parantheses. void parenthesesHelper(int index) { double value = 0; for(size_t i = index; i < formula.size() - index; i++) { string singleVal = formula[i]; if (singleVal[0] == '(') { int count = 0; int j = i + 1; string parFinder = formula[j]; string problem = ""; // Recursively computes multiple parentheses while (parFinder[0] != ')') { if(parFinder[0] == '(') { parenthesesHelper(j); } problem = problem + formula[j]; count++; j++; parFinder = formula[j]; } if (count > 3) { Calculator calc; calc.enterExpression(problem); calc.parentheses(); calc.exponent(); calc.multiplyOrDiv(); calc.additionOrSub(); formula.erase(formula.begin() + i); for(size_t k = 0; k < (size_t)count; k++) { formula.erase(formula.begin() + i); } formula.erase(formula.begin() + i); string valString = numToString(calc.getTotal()); formula.insert(formula.begin() + i, valString); } else { string op = formula[i + 2]; string left = formula[i + 1]; string right = formula[i + 3]; double operandL = stringToNum(left); double operandR = stringToNum(right); if (op[0] == '^') { value = 1; for (int j = 0; j < operandR; j++) {; value *= operandL; } } else if (op[0] == '*') { value = operandL * operandR; } else if (op[0] == '/') { value = operandL / operandR; } else if (op[0] == '+') { value = operandL + operandR; } else if (op[0] == '-' && op.length() == 1) { value = operandL - operandR; } string valString = numToString(value); formula.erase(formula.begin() + i); formula.erase(formula.begin() + i); formula.erase(formula.begin() + i); formula.erase(formula.begin() + i); formula.erase(formula.begin() + i); formula.insert(formula.begin() + i, valString); } } } }
Для других операторов:
void solve(int exponent, int multOrDiv, int addOrSub) { double value = 0; for(size_t i = 0; i < formula.size(); i++) { string s = formula[i]; // Ensures no other operator except the current one is being evaluated. if ((operators.count(s[0]) && (s[0] == '^') && exponent) || (operators.count(s[0]) && (s[0] == '*' || s[0] == '/') && multOrDiv) || (operators.count(s[0]) && (s[0] == '+' || (s[0] == '-' && s.length() == 1)) && addOrSub)) { string left = formula[i - 1]; string right = formula[i + 1]; double operandL = stringToNum(left); double operandR = stringToNum(right); if (exponent) { if (s[0] == '^') { value = 1; for (int j = 0; j < operandR; j++) { value *= operandL; } } } else if (multOrDiv) { if (s[0] == '*') { value = operandL * operandR; } else if (s[0] == '/') { value = operandL / operandR; } } else if (addOrSub) { if (s[0] == '+') { value = operandL + operandR; } else if (s[0] == '-' && s.length() == 1) { value = operandL - operandR; } } string valString = numToString(value); formula.erase(formula.begin() + i - 1); formula.erase(formula.begin() + i - 1); formula.erase(formula.begin() + i - 1); formula.insert(formula.begin() + i - 1, valString); i = 0; } } }
Эти два метода просматривают выражение слева направо и решают его в зависимости от того, что является приоритетным в данный момент. Какой подход был бы лучше?
Вот это по полной программе
/* * Calculator * * This program calculates arithmetic expressions * and strictly follows the PEMDAS order of operations. * (Note: Assumes the user will input valid expressions) * */ #include <string> #include <cstdlib> #include <vector> #include <set> #include <sstream> #include <iostream> using namespace std; class Calculator { public: // Initializes the Calculator class. Calculator() { total = 0.0; operators.insert('('); operators.insert(')'); operators.insert('^'); operators.insert('*'); operators.insert('/'); operators.insert('+'); operators.insert('-'); } // Passes in a string that represents the arithmetic // expression to be solved. The expression can contain // spaces, and assumes that the arithmetic expression is valid. void enterExpression(string problem) { // Gets rid of spaces within the expression. for(size_t i = 0; i < problem.length(); i++) { char space = problem[i]; if (space != ' ') { string s(1, problem[i]); expression += s; } } // Strings together values larger than 9 (more than one digit) for(size_t i = 0; i < expression.size(); i++) { string bigDigit = ""; if ((expression[i] <= '9' && expression[i] >= '0') || expression[i] == '.' || (expression[i] == '-' && i == 0) ) { while((expression[i] <= '9' && expression[i] >= '0') || expression[i] == '.' || (expression[i] == '-' && i == 0) ) { string temp(1, expression[i]); bigDigit = bigDigit + temp; i++; } formula.push_back(bigDigit); } string temp(1, expression[i]); formula.push_back(temp); } } // Solves expressions that contain parantheses. void parentheses() { if (formula.size() > 2) { parenthesesHelper(0); if(numCheck()) { total = stringToNum(formula[0]); } } } // Solves expressions that contain exponents. void exponent() { if (formula.size() > 2) { solve(1, 0, 0); if (numCheck()) { total = stringToNum(formula[0]); } } } // Solves expressions that contain either multiplication or division (or both). void multiplyOrDiv() { if (formula.size() > 2) { solve(0, 1, 0); if(numCheck()) { total = stringToNum(formula[0]); } } } // Solves expressions that contain either addition or subtraction (or both). void additionOrSub() { if (formula.size() > 2) { solve(0, 0, 1); double val = stringToNum(formula[0]); if(numCheck() || (formula.size() <= 2 && val < 0)) { total = stringToNum(formula[0]); } } } // Displays the content of the current expression being solved. void display() { for(size_t i = 0; i < formula.size(); i++) { string s = formula[i]; cout << "" << s; } cout << endl; } // Passes in a string and returns the decimal representation of it. double stringToNum(string s) { double val = 0.0; stringstream(s) >> val; return val; } // Passes in a number and returns the string representation of it. string numToString(double val) { ostringstream strs; strs <<
TL;DR: Я просто хочу знать, как еще решать арифметические выражения на C++ объектно-ориентированным способом без использования алгоритма маневрового двора, а также хотел бы получить советы по коду C++, чтобы я мог стать лучше.
Что я уже пробовал:
Я определенно знаю, что не писал хорошего кода, поэтому могу понять, почему они приняли то решение, которое они приняли. Я мог бы очистить код, удалить некоторую избыточность (например, каким-то образом объединить метод solve и метод скобок) и написать метод, который проверяет, является ли выражение допустимым, но у меня было ограничение по времени, и они сказали мне, что единственное, что для них имеет значение, - это подход (который им не нравился, ха-ха). Опять же, какой подход был бы лучше? Кроме того, я приветствую все критические замечания по поводу моего кодирования, потому что я знаю, что могу написать какой-то s*** код, и я пытаюсь его очистить.