eckogame Ответов: 1

Еще один способ решения арифметических выражений в 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*** код, и я пытаюсь его очистить.

1 Ответов

Рейтинг:
0

KarstenK

Главным недостатком вашей реализации может быть то, что она не очень объектно-ориентирована. И оператор сканирования должен в объект.

Таким образом, открывающая скобка должна создавать подрасчет, и эти результаты являются входными данными для родительского расчета.

Пример = ( 2 + 3 ) * 4

должен быть внутренне отсканирован, чтобы:
Расчет( (расчет(2, Добавить,3), умножить, 4 );// Добавить и умножить должно быть перечислений, который функции "фабрики" или конструктор обнаруживает. (Мне не нравятся сложные ctors, потому что проблемы обработки ошибок)

PS: решение о том, какой кодер получит эту работу, заключается в следующем в основном в зависимости от зарплаты или некоторых "мягких навыков", которые предоставляют место для личных чувств.