Una calculadora de línea de comandos usando INFIX a POSTFIX en C ++ -- ++ campo con algorithm campo con math-expression-eval camp codereview Relacionados El problema

A command-line calculator using infix to postfix in C++


5
vote

problema

Español

Estaba de humor para algunos C ++ y decidí escribir una calculadora de línea de comandos, que entiende la adición, la resta, la multiplicación y los paréntesis. Mira lo que tengo:

main.cpp

  #include <algorithm> #include <cctype> #include <iostream> #include <iterator> #include <sstream> #include <stack> #include <stdexcept> #include <utility> #include <vector>  using std::cin; using std::copy; using std::cout; using std::endl; using std::isspace; using std::ostream_iterator; using std::pair; using std::runtime_error; using std::stack; using std::string; using std::stringstream; using std::vector;  enum class TokenType {     OPERAND,     OPERATOR };  enum class Operator {     PLUS,     MINUS,     MULTIPLY,     LEFT_PARENTHESIS,     RIGHT_PARENTHESIS };   static int get_operator_precedence(Operator _operator) {     switch (_operator) {         case Operator::PLUS:         case Operator::MINUS:             return 1;          case Operator::MULTIPLY:             return 0;          default:              if (_operator == Operator::LEFT_PARENTHESIS)             {                 throw runtime_error(                     "Left parenthesis has no precedence assigned to it.");             }              if (_operator == Operator::RIGHT_PARENTHESIS)             {                 throw runtime_error(                     "Right parenthesis has no precedence assigned to it.");             }              throw std::runtime_error(                     "Unknown operator. This should not happen.");     } }  class Token {     TokenType m_token_type;     Operator  m_operator;     int       m_operand;  public:     Token(int operand) : m_operand{operand},                          m_token_type{TokenType::OPERAND} {}      Token(Operator _operator) : m_operand{0},                                 m_token_type(TokenType::OPERATOR),                                 m_operator{_operator} {}      TokenType get_token_type() const     {         return m_token_type;     }      Operator get_operator() const     {         return m_operator;     }      int get_operand() const     {         return m_operand;     }      friend std::ostream& operator<<(std::ostream&, const Token&); };  std::ostream& operator<<(std::ostream& out, const Token& token) {     if (token.m_token_type == TokenType::OPERAND)     {         out << token.m_operand;     }     else     {         switch (token.m_operator)         {             case Operator::PLUS:                 out << "+";                 break;              case Operator::MINUS:                 out << "-";                 break;              case Operator::MULTIPLY:                 out << "*";                 break;              case Operator::LEFT_PARENTHESIS:                 out << "(";                 break;              case Operator::RIGHT_PARENTHESIS:                 out << ")";                 break;         }     }      return out; }  vector<Token> tokenize(const string& expression) {     vector<Token> token_vector;     stringstream number_string_stream;     bool number_string_stream_empty = true;     size_t char_index = 0;     size_t expression_length = expression.length();      while (char_index < expression_length)     {         const char current_char = expression[char_index];          switch (current_char)         {             case '(':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::LEFT_PARENTHESIS));                 break;              case ')':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::RIGHT_PARENTHESIS));                 break;              case '+':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::PLUS));                 break;              case '-':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::MINUS));                 break;              case '*':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::MULTIPLY));                 break;              case '0':             case '1':             case '2':             case '3':             case '4':             case '5':             case '6':             case '7':             case '8':             case '9':                  number_string_stream_empty = false;                 number_string_stream << current_char;                 break;              default:                 if (!isspace(current_char))                 {                     stringstream err_msg;                      err_msg << "Bad character: '"                             << current_char                             << "' at index "                             << char_index                             << "!";                      throw runtime_error(err_msg.str());                 }         }          ++char_index;     }      if (!number_string_stream_empty)     {         int operand;         number_string_stream >> operand;         token_vector.push_back(Token(operand));     }      return token_vector; }  vector<Token> shunting_yard_algorithm(const vector<Token>& token_vector) {     vector<Token> postfix_token_vector;     stack<Token> operator_stack;      for (const Token& token : token_vector)     {         if (token.get_token_type() == TokenType::OPERAND)         {             postfix_token_vector.push_back(token);         }         else if (token.get_operator() == Operator::LEFT_PARENTHESIS)         {             operator_stack.push(token);         }         else if (token.get_operator() == Operator::RIGHT_PARENTHESIS)         {             while (!operator_stack.empty()                    && operator_stack.top().get_operator()                    != Operator::LEFT_PARENTHESIS)             {                 postfix_token_vector.push_back(operator_stack.top());                 operator_stack.pop();             }              if (operator_stack.empty()                 || operator_stack.top().get_operator()                         != Operator::LEFT_PARENTHESIS)             {                 throw runtime_error("The parentheses are invalid.");             }             else             {                 operator_stack.pop();             }         }         else         {             while (!operator_stack.empty()                    && operator_stack.top().get_operator()                         != Operator::LEFT_PARENTHESIS                    && get_operator_precedence(                         operator_stack.top().get_operator()) <                         get_operator_precedence(token.get_operator()))             {                 postfix_token_vector.push_back(operator_stack.top());                 operator_stack.pop();             }              operator_stack.push(token);         }      }      while (!operator_stack.empty())     {         postfix_token_vector.push_back(operator_stack.top());         operator_stack.pop();     }      return postfix_token_vector; }  pair<int, vector<Token>> coderodde_evaluate(const string& expression) {     vector<Token> infix_token_vector = tokenize(expression);     vector<Token> postfix_token_vector =         shunting_yard_algorithm(infix_token_vector);      stack<Token> _stack;      for (const Token& token : postfix_token_vector)     {         if (token.get_token_type() == TokenType::OPERATOR             && token.get_operator() == Operator::LEFT_PARENTHESIS)         {             throw runtime_error(                 "The parentheses are invalid.");         }          if (token.get_token_type() == TokenType::OPERAND)         {             _stack.push(token.get_operand());         }         else         {             if (_stack.size() < 2)             {                 throw runtime_error("The parentheses are invalid.");             }              int operand2 = _stack.top().get_operand(); _stack.pop();             int operand1 = _stack.top().get_operand(); _stack.pop();              switch (token.get_operator())             {                 case Operator::PLUS:                     _stack.push(Token(operand1 + operand2));                     break;                  case Operator::MINUS:                     _stack.push(Token(operand1 - operand2));                     break;                  case Operator::MULTIPLY:                     _stack.push(Token(operand1 * operand2));                     break;             }         }     }      if (_stack.size() != 1)     {         throw runtime_error("The parentheses are invalid.");     }      return make_pair(_stack.top().get_operand(), postfix_token_vector); }  int main() {     string expr;      while (true)     {         cout << "> ";         getline(cin, expr);          if (expr == "quit")         {             break;         }          try {             pair<int, vector<Token>> data = coderodde_evaluate(expr);             cout << "Value: " << data.first << ", postfix notation: ";              copy(data.second.cbegin(),                  data.second.cend(),                  ostream_iterator<Token>(cout, " "));              cout << endl;         }         catch (runtime_error& err)         {             cout << "ERROR: " << err.what() << endl;         }     } }   

Solicitud de crítica

¿Estoy haciendo buenos C ++ aquí? Por favor, dime algo que viene a la mente.

Original en ingles

I was in the mood for some C++ and decided to write a command line calculator, which understands addition, subtraction, multiplication and parentheses. See what I have:

main.cpp

#include <algorithm> #include <cctype> #include <iostream> #include <iterator> #include <sstream> #include <stack> #include <stdexcept> #include <utility> #include <vector>  using std::cin; using std::copy; using std::cout; using std::endl; using std::isspace; using std::ostream_iterator; using std::pair; using std::runtime_error; using std::stack; using std::string; using std::stringstream; using std::vector;  enum class TokenType {     OPERAND,     OPERATOR };  enum class Operator {     PLUS,     MINUS,     MULTIPLY,     LEFT_PARENTHESIS,     RIGHT_PARENTHESIS };   static int get_operator_precedence(Operator _operator) {     switch (_operator) {         case Operator::PLUS:         case Operator::MINUS:             return 1;          case Operator::MULTIPLY:             return 0;          default:              if (_operator == Operator::LEFT_PARENTHESIS)             {                 throw runtime_error(                     "Left parenthesis has no precedence assigned to it.");             }              if (_operator == Operator::RIGHT_PARENTHESIS)             {                 throw runtime_error(                     "Right parenthesis has no precedence assigned to it.");             }              throw std::runtime_error(                     "Unknown operator. This should not happen.");     } }  class Token {     TokenType m_token_type;     Operator  m_operator;     int       m_operand;  public:     Token(int operand) : m_operand{operand},                          m_token_type{TokenType::OPERAND} {}      Token(Operator _operator) : m_operand{0},                                 m_token_type(TokenType::OPERATOR),                                 m_operator{_operator} {}      TokenType get_token_type() const     {         return m_token_type;     }      Operator get_operator() const     {         return m_operator;     }      int get_operand() const     {         return m_operand;     }      friend std::ostream& operator<<(std::ostream&, const Token&); };  std::ostream& operator<<(std::ostream& out, const Token& token) {     if (token.m_token_type == TokenType::OPERAND)     {         out << token.m_operand;     }     else     {         switch (token.m_operator)         {             case Operator::PLUS:                 out << "+";                 break;              case Operator::MINUS:                 out << "-";                 break;              case Operator::MULTIPLY:                 out << "*";                 break;              case Operator::LEFT_PARENTHESIS:                 out << "(";                 break;              case Operator::RIGHT_PARENTHESIS:                 out << ")";                 break;         }     }      return out; }  vector<Token> tokenize(const string& expression) {     vector<Token> token_vector;     stringstream number_string_stream;     bool number_string_stream_empty = true;     size_t char_index = 0;     size_t expression_length = expression.length();      while (char_index < expression_length)     {         const char current_char = expression[char_index];          switch (current_char)         {             case '(':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::LEFT_PARENTHESIS));                 break;              case ')':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::RIGHT_PARENTHESIS));                 break;              case '+':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::PLUS));                 break;              case '-':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::MINUS));                 break;              case '*':                  if (!number_string_stream_empty)                 {                     int number;                     number_string_stream >> number;                     number_string_stream.clear();                     token_vector.push_back(Token(number));                     number_string_stream_empty = true;                 }                  token_vector.push_back(Token(Operator::MULTIPLY));                 break;              case '0':             case '1':             case '2':             case '3':             case '4':             case '5':             case '6':             case '7':             case '8':             case '9':                  number_string_stream_empty = false;                 number_string_stream << current_char;                 break;              default:                 if (!isspace(current_char))                 {                     stringstream err_msg;                      err_msg << "Bad character: '"                             << current_char                             << "' at index "                             << char_index                             << "!";                      throw runtime_error(err_msg.str());                 }         }          ++char_index;     }      if (!number_string_stream_empty)     {         int operand;         number_string_stream >> operand;         token_vector.push_back(Token(operand));     }      return token_vector; }  vector<Token> shunting_yard_algorithm(const vector<Token>& token_vector) {     vector<Token> postfix_token_vector;     stack<Token> operator_stack;      for (const Token& token : token_vector)     {         if (token.get_token_type() == TokenType::OPERAND)         {             postfix_token_vector.push_back(token);         }         else if (token.get_operator() == Operator::LEFT_PARENTHESIS)         {             operator_stack.push(token);         }         else if (token.get_operator() == Operator::RIGHT_PARENTHESIS)         {             while (!operator_stack.empty()                    && operator_stack.top().get_operator()                    != Operator::LEFT_PARENTHESIS)             {                 postfix_token_vector.push_back(operator_stack.top());                 operator_stack.pop();             }              if (operator_stack.empty()                 || operator_stack.top().get_operator()                         != Operator::LEFT_PARENTHESIS)             {                 throw runtime_error("The parentheses are invalid.");             }             else             {                 operator_stack.pop();             }         }         else         {             while (!operator_stack.empty()                    && operator_stack.top().get_operator()                         != Operator::LEFT_PARENTHESIS                    && get_operator_precedence(                         operator_stack.top().get_operator()) <                         get_operator_precedence(token.get_operator()))             {                 postfix_token_vector.push_back(operator_stack.top());                 operator_stack.pop();             }              operator_stack.push(token);         }      }      while (!operator_stack.empty())     {         postfix_token_vector.push_back(operator_stack.top());         operator_stack.pop();     }      return postfix_token_vector; }  pair<int, vector<Token>> coderodde_evaluate(const string& expression) {     vector<Token> infix_token_vector = tokenize(expression);     vector<Token> postfix_token_vector =         shunting_yard_algorithm(infix_token_vector);      stack<Token> _stack;      for (const Token& token : postfix_token_vector)     {         if (token.get_token_type() == TokenType::OPERATOR             && token.get_operator() == Operator::LEFT_PARENTHESIS)         {             throw runtime_error(                 "The parentheses are invalid.");         }          if (token.get_token_type() == TokenType::OPERAND)         {             _stack.push(token.get_operand());         }         else         {             if (_stack.size() < 2)             {                 throw runtime_error("The parentheses are invalid.");             }              int operand2 = _stack.top().get_operand(); _stack.pop();             int operand1 = _stack.top().get_operand(); _stack.pop();              switch (token.get_operator())             {                 case Operator::PLUS:                     _stack.push(Token(operand1 + operand2));                     break;                  case Operator::MINUS:                     _stack.push(Token(operand1 - operand2));                     break;                  case Operator::MULTIPLY:                     _stack.push(Token(operand1 * operand2));                     break;             }         }     }      if (_stack.size() != 1)     {         throw runtime_error("The parentheses are invalid.");     }      return make_pair(_stack.top().get_operand(), postfix_token_vector); }  int main() {     string expr;      while (true)     {         cout << "> ";         getline(cin, expr);          if (expr == "quit")         {             break;         }          try {             pair<int, vector<Token>> data = coderodde_evaluate(expr);             cout << "Value: " << data.first << ", postfix notation: ";              copy(data.second.cbegin(),                  data.second.cend(),                  ostream_iterator<Token>(cout, " "));              cout << endl;         }         catch (runtime_error& err)         {             cout << "ERROR: " << err.what() << endl;         }     } } 

Critique request

Am I doing good C++ here? Please tell me anything that comes to mind.

        
     
     

Lista de respuestas

4
 
vote
vote
La mejor respuesta
 

bastante bonito. Un par de cosas pequeñas:

  • Puede usar emplace_back en lugar de push_back Al agregar tokens. Del mismo modo para la pila con emplace en lugar de push
  • Por el bien de la simetría, haz out << 'c' en lugar de out << "c"
  • Revise su IO: su MaineLoop debe ser while (getline(cin, expr)) { ... }8 Para detectar EOF
  • No use struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 0 para nombres.
 

Quite nice. A couple of small things:

  • you can use emplace_back instead of push_back when adding Tokens. Likewise for the stack with emplace instead of push
  • for the sake of symetry, do out << 'c' instead of out << "c"
  • check your IO: your mainloop should be while (getline(cin, expr)) { ... } to detect EOF
  • don't use _variable for names.
 
 
 
 
2
 
vote

Esta sugerencia probablemente no hará que el código se vea más como C ++.

Análisis, la entrada de tokenización es un trabajo muy engorroso. Tiene muchos casos de borde. Cuando sea posible, se debe implementar una biblioteca de muy alta calidad. Puede ser demasiado complicado, pero uno de ellos es Boost .spirit Familia de bibliotecas. Se basa en plantillas de expresión .

Eres struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 1 Demasiado. El único caso que debe escribir struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 2 es la instrucción Switch, que se realiza para permitir que el compilador elija la sobrecarga de función adecuada. Simplemente escriba struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 3 donde debe escribirse.

No use los prefijos M_. Son artefactos del pasado. Buena razón para enriquecer el vocabulario (pero no escriba palabras demasiado sofisticadas para que otras personas puedan entender).

 

This suggestion probably won't make the code look more like C++.

Parsing, tokenizing input is very cumbersome job. It has a lot of edge cases. When possible, very high quality library should be deployed. It might be overkill, but one of them is boost.spirit family of libraries. It is based on expression templates.

You're using too much. The only case you should write using is switch statement, which is done to let the compiler choose appropriate function overload. Just write std:: where it should be written.

Don't use m_ prefixes. They are artifacts of the past. Good reason to enrich vocabulary (but don't write too sophisticated words so other people could understand ).

 
 
2
 
vote

nombres de funciones descriptivas

Es un tipo de extraño para nombrar su análisis después de usted mismo struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 4 . Sugiere que lo está evaluando (a menos que CODERODDE tenga algún significado que no conozco). Prefiero un nombre que describa lo que realmente hace la función. Si desea empaquetar sus cosas, piense en usar espacios de nombres en su lugar.

Los paréntesis no son válidos.

Tiras errores de tiempo de ejecución con la cadena misma de la cadena 'Los paréntesis no son válidos'. 4 veces en su código. Esto sugiere que tal vez debe definirse como una constante. También es, algo confuso para el usuario:

   struct url *init_url()  {       struct url *u = (struct url*)malloc(sizeof(struct url));       if (u != NULL)           memset(u, 0, sizeof(struct url));       return u   }     5  

No he usado ningún paréntesis ...

Comprobación de desbordamiento

No limita el tamaño del flujo de entrada, por lo que es posible desbordar la entrada:

   struct url *init_url()  {       struct url *u = (struct url*)malloc(sizeof(struct url));       if (u != NULL)           memset(u, 0, sizeof(struct url));       return u   }     6  

espacios

Esto es probablemente subjetivo, pero me parece extraño que permitas espacios entre números:

   struct url *init_url()  {       struct url *u = (struct url*)malloc(sizeof(struct url));       if (u != NULL)           memset(u, 0, sizeof(struct url));       return u   }     7  

enum valores

de nuevo, algo subjetivo, pero me sentiría tentado a asignar valores a su operador enum como:

   struct url *init_url()  {       struct url *u = (struct url*)malloc(sizeof(struct url));       if (u != NULL)           memset(u, 0, sizeof(struct url));       return u   }     8  

De esa manera, el valor del enume está en realidad vinculado al carácter que representa. Esto hace posible que su struct url *init_url() { struct url *u = (struct url*)malloc(sizeof(struct url)); if (u != NULL) memset(u, 0, sizeof(struct url)); return u } 9 se convierta en:

  emplace_back0  
 

Descriptive function names

It's kind of weird to name your parsing after yourself coderodde_evaluate. It suggests it's evaluating you (unless coderodde has some meaning I don't know about). I'd prefer a name that describes what the function actually does. If you want to package your stuff, think about using namespaces instead.

The parentheses are invalid.

You throw runtime errors with the string same string 'The parentheses are invalid.' 4 times in your code. This suggests that maybe it should be defined as a constant. It's also, somewhat confusing to the user:

> 1* ERROR: The parentheses are invalid. > * ERROR: The parentheses are invalid. > ERROR: The parentheses are invalid. 

I haven't used any parentheses...

Overflow checking

You don't limit the size of the input stream, so it's possible to overflow the input:

> 11111111111111111111 Value: -858993460, postfix notation: -858993460 

Spaces

This is probably subjective, but I find it odd that you allow spaces between numbers:

> 2*(2 1 3 4 5 6 7) Value: 4269134, postfix notation: 2 2134567 * 

Enum Values

Again, somewhat subjective, but I'd be tempted to assign values to your operator enum like:

enum class Operator {     PLUS='+',     MINUS='-',     MULTIPLY='*',     LEFT_PARENTHESIS='(',     RIGHT_PARENTHESIS=')' }; 

That way the value of the enum is actually linked to the character it represents. This makes it possible for your operator<< to become:

std::ostream& operator<<(std::ostream& out, const Token& token) {     if (token.m_token_type == TokenType::OPERAND)     {         out << token.m_operand;     }     else     {         out << static_cast<char>(token.m_operator);     }     return out; } 
 
 

Relacionados problema

2  Expresión de infijo (con números negativos) a Postfix  ( Infix expression with negative numbers to postfix ) 
Estoy escribiendo una clase para evaluar una expresión aritmética, ya que ahora mi clase puede convertir una expresión de infijo en PostFix, todavía no admite...

3  La calculadora recursiva basada en RPN-STACK necesita TuneUp  ( Rpn stack based recursive calculator needs tuneup ) 
Esta función toma una serie de cuerdas y números y la procesa recursivamente como un tipo de "programa de cálculo". La estructura se basa en la notación de po...

8  Codewars Evaluador de expresión matemática  ( Codewars mathematical expresion evaluator ) 
Recientemente escribí el siguiente código para un Codewars.com Kata para evaluar las expresiones matemáticas . He estado escribiendo Ruby durante años, pero ...

3  Calculadora de RPN de NASM  ( Nasm rpn calculator ) 
He estado aprendiendo ensamblaje en los últimos días, y he hecho una simple calculadora RPN. Aquí está la lógica principal del programa, excluyendo las func...

2  Verificación de expresiones matemáticas  ( Verifying mathematical expressions ) 
Esta es una parte de mi programa de calculadora. Tengo que verificar si la entrada ingresada por el usuario es una expresión matemática válida. El primer prog...

1  Parser Ecuación + Solver  ( Equation parser solver ) 
Aquí hay un analizador de la ecuación que acabo de escribir. Mi enfoque fue la legibilidad y la perspectiva de agregar nuevas características en el futuro. Co...

6  Programa de Convertidor de Infix a Postfix  ( Infix to postfix converter program ) 
Esta es mi tarea. Amablemente ayúdame a verificarlo? Las instrucciones son: Implementar una expresión de infIX en el convertidor de expresión postfix. De...

3  Análisis de expresión (solo operadores aritméticos)  ( Expression parsing arithmetic operators only ) 
Como un proyecto de auto-aprendizaje, escribí un analizador de expresión utilizando el algoritmo de la derivación del patio en JavaScript. Es una parte más gr...

5  Calculadora de derivados algebraica estándar  ( Standard algebraic derivative calculator ) 
Tuve alguna dificultad con este problema, así que estoy seguro de que hay una mejor manera. Aquí está la pregunta de SICP : ejercicio 2.58 Supongamos ...

1  Evaluando una expresión aritmética de un árbol binario  ( Evaluating an arithmetic expression from a binary tree ) 
Digamos que tengo un árbol binario que se ve + 2 * 5 8 He escrito una función para atravesar el inicio para resolverl...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos