使用堆栈的Postfix表达式求值

时间:2019-04-04 03:41:35

标签: c++

我正在使用+,-,*,/和^运算符编写用于后缀表达式评估的代码。它应该从命令行将输入作为字符串,该字符串是表达式的后记符号(空格用作定界符)。该程序应在控制台上打印表达式的结果。

我编写的代码适用于所有带有整数值的测试用例。例如。它适用于输入:2 2 2 * + 我试图将堆栈输入值更改为float而不是int,但仍然无法使用。

using namespace std;
struct node
{
    float data ;
    node *next ;
};
class stack
{
    private : 
    node *head;
    public :
    stack()
    {
        head = NULL;
    }
    void push(float a)
    {
        node * temp = new node();
        temp ->data = a ;
        temp -> next = head ; 
        head = temp ;
    }
    int pop()
    {
        node *temp = head ;
        head = temp->next ;
        int a = temp->data ;
        delete temp;
        return a;
    }
    int see_top()
    {
        if(is_empty())
            return 0 ;
        node * temp = head ;
        return (temp->data);
    }
    int is_empty()
    {
        if(head == NULL)
            return 1;
        else
            return 0 ;
    }
};
int is_digit(char a)
{
    if(a >= '0' && a<= '9')
        return 1;
    else
        return 0;
}
int is_operand(char a)
{
    switch(a)
    {
        case '+' :
        case '-' :
        case '*' : 
        case '/' : 
        case '^' : return 1;
        default  : return 0;
    }
}

float operation(float a , float b , char sym)
{
    float ans ;
    switch(sym)
    {
        case '+' : ans = a + b ;
               break;
        case '-' : ans = a - b ;
               break ;
        case '*' : ans = a*b ;
               break ;
        case '/' : ans = a/b ;
               break ;
        case '^' : ans = pow(a,b) ;
               break ;
        default  : break ;
    }
    return ans ;
}
int main()
{
    char exp[100];
    stack s ; 
    float  num=0 , num1=0 , num2=0 ;
    int l , i ;
    cout << "Enter the posfix expression : ";
    cin.getline(exp,100);
    l=strlen(exp);
    for(i=0;i<l;i++)
    {
        if(is_digit(exp[i]))
        {
            num = 0;
            while(exp[i]!=' ')
            {
                int a = exp[i++]- '0';
                num = 10*num + a ;
            }
            s.push(num);
        }
        else if(is_operand(exp[i]))
        {
            num2 = s.see_top();
            s.pop();
            num1 = s.see_top();
            s.pop();
            num = operation(num1 , num2 , exp[i]);
            s.push(num);
        }
        else
            continue;
    }

    num = s.see_top();
    s.pop();
    cout << "Answer : " << num ;
    return 0 ;
}

当我尝试输入带有一些浮点值的表达式时,它没有返回正确的值。例如。理想情况下,对于表达式0.5 0.5 *,应返回0.25,但应返回225。对于表达式0.1 0.1 +,则应返回-36。

1 个答案:

答案 0 :(得分:0)

代码看起来非常好!

您快到了。代码中存在三个问题:

  • pop()将所有内容强制转换为int
  • see_top()将所有内容强制转换为int
  • 小数点解析不起作用。

这是更新后的pop()see_top()注意,他们现在返回浮点数。

float pop()
{
  node *temp = head;
  head = temp->next;
  float a = temp->data;
  delete temp;
  return a;
}
float see_top()
{
  if (is_empty())
    return 0;
  node *temp = head;
  return (temp->data);
}

解析小数点最好通过添加switch语句来解决。

看到小数点后,您实际上就进入了新状态。请参见下面的代码。我还添加了代码来处理“-”字符。我使用pow()数学函数添加数字的小数部分。我会将数字解析移到一个函数中,但不想完全更改您的代码。这是完整的解决方案:

#include <cmath>
#include <iostream>

using namespace std;
struct node {
    float data;
    node *next;
};
class stack {
private :
    node *head;
public :
    stack()
    {
      head = NULL;
    }
    void push(float a)
    {
      node *temp = new node();
      temp->data = a;
      temp->next = head;
      head = temp;
    }
    float pop()
    {
      node *temp = head;
      head = temp->next;
      float a = temp->data;
      delete temp;
      return a;
    }
    float see_top()
    {
      if (is_empty())
        return 0;
      node *temp = head;
      return (temp->data);
    }
    int is_empty()
    {
      if (head == NULL)
        return 1;
      else
        return 0;
    }
};
bool is_digit(char a)
{
  return (a >= '0' && a <= '9') || a == '.' || a == '-';
}
bool is_operand(char a)
{
  switch (a) {
    case '+' :
    case '-' :
    case '*' :
    case '/' :
    case '^' : return true;
    default  : return false;
  }
}

float operation(float a, float b, char sym)
{
  float ans;
  switch (sym) {
    case '+' : ans = a + b;
      break;
    case '-' : ans = a - b;
      break;
    case '*' : ans = a * b;
      break;
    case '/' : ans = a / b;
      break;
    case '^' : ans = pow(a, b);
      break;
    default  : break;
  }
  return ans;
}

int main()
{
  char exp[100];
  stack s;
  float num = 0, num1 = 0, num2 = 0;
  int l, i;
  cout << "Enter the posfix expression : ";
  cin.getline(exp, 100);
  l = strlen(exp);
  for (i = 0; i < l; i++) {
    int exponent = 0;
    int sign = 1;

    if (is_digit(exp[i])) {
      num = 0;
      while (exp[i] != ' ') {
        switch (exp[i]) {
          case '.':exponent = -1;
            break;
          case '-':
            sign = -1; // handle the negative sign
            break;
          default:int a = exp[i] - '0';
            if(exponent >= 0) {
              num = pow(10, exponent) * num + a;
                ++exponent;
            } else {
              num = pow(10, exponent) * a + num;
              --exponent;
            }
        }
        ++i;
      }
      num *= sign;  // If there was a '-', multiply by -1
      s.push(num);
    } else if (is_operand(exp[i])) {
      num2 = s.see_top();
      s.pop();
      num1 = s.see_top();
      s.pop();
      num = operation(num1, num2, exp[i]);
      s.push(num);
    } else
      continue;
  }

  num = s.see_top();
  s.pop();
  cout << "Answer : " << num;
  return 0;
}

使用std :: istringstream的替代解决方案

为了获得一些额外的乐趣,我重写了一些输入处理以使用std :: istringstream。 stringstream非常强大,在解析时应始终考虑在内。我发现将字符串加倍转换为c ++的函数令人困惑并且容易出错。因此,如果允许您使用stringstream,这可能会有所帮助。由于stringstream将为您完成转换,因此无需搜索小数点。它将处理所有边缘情况。这是stringstream解决方案:

#include <iostream>
#include <cmath>
#include <sstream>

using namespace std;
struct node {
    float data;
    node *next;
};
class stack {
private :
    node *head;
public :
    stack()
    {
      head = NULL;
    }
    void push(float a)
    {
      node *temp = new node();
      temp->data = a;
      temp->next = head;
      head = temp;
    }
    float pop()
    {
      node *temp = head;
      head = temp->next;
      float a = temp->data;
      delete temp;
      return a;
    }
    float see_top()
    {
      if (is_empty())
        return 0;
      node *temp = head;
      return (temp->data);
    }
    bool is_empty()
    {
      if (head == NULL)
        return true;
      else
        return false;
    }
};

int is_digit(char a)
{
  if (a >= '0' && a <= '9')
    return 1;
  else
    return 0;
}
int is_operand(char a)
{
  switch (a) {
    case '+' :
    case '-' :
    case '*' :
    case '/' :
    case '^' : return 1;
    default  : return 0;
  }
}

float operation(float a, float b, char sym)
{
  float ans;
  switch (sym) {
    case '+' : ans = a + b;
      break;
    case '-' : ans = a - b;
      break;
    case '*' : ans = a * b;
      break;
    case '/' : ans = a / b;
      break;
    case '^' : ans = pow(a, b);
      break;
    default  : break;
  }
  return ans;
}

int main()
{
  //  char exp[100];
  stack s;
  float num = 0, num1 = 0, num2 = 0;

  cout << "Enter the posfix expression : ";

  std::string input_line;
  std::getline(cin, input_line);
  std::istringstream token_stream(input_line); // Parse words from input_line
  std::string token;

  while (token_stream >> token) {
    // Check the first character of the token.  It is n operand, then use it
    //  You could move the size() check to the is_operand() function
    if (token.size() == 1 && is_operand(token[0])) {
      char operand = token[0];
      num2 = s.see_top();
      s.pop();
      num1 = s.see_top();
      s.pop();
      num = operation(num1, num2, operand);
      s.push(num);
    } else {
      std::istringstream number_stream(token);  // convert number tokens to floats

      if(number_stream >> num) {
        s.push(num);
      }

    }
  }

  num = s.see_top();
  s.pop();
  cout << "Answer : " << num;
  return 0;
}