《C++ Primer》练习9.52:使用栈实现四则运算

栈可以用来使用四则运算,是一个稍微有点复杂的题目,去学习了一下用栈实现四则运算的原理,用C++实现了一下。首先要把常见的中缀表达式改成后缀表达式,然后通过后缀表达式计算,具体的原理可以参考这位博主的文章:C语言数据结构篇------用栈实现四则运算,在数和运算符之间都加入了空格来进行分隔,方便后续的提取有效数据处理。

代码还有优化的地方,先记录一下吧:

cpp 复制代码
#include <iostream>
#include <string>
#include <stack>
using namespace std;

int getOperatorPriority(char &a)
{
  int res;
  if (a == '(')
    res = 0;
  else if (a == '+' || a == '-')
    res = 1;
  else if (a == '*' || a == '/')
    res = 2;
  else if (a == ')')
    res = 3;

  return res;
}
bool compareOperatorPriority(char &a, char &b)
{
  int a_res = getOperatorPriority(a);
  int b_res = getOperatorPriority(b);
  return a_res >= b_res;
}

string createBackSeq(string &str)
{
  stack<char> sak;
  string str2;
  int seen = 0;
  int p = 0;
  for (int i = 0; i != str.size(); ++i)
  {
    if (isdigit(str[i]))
    {
      str2.append(str.substr(i, 1));
      if ((i + 1 != str.size() && !isdigit(str[i + 1])) || i == str.size() - 1)
        str2.append(" ");
    }

    else
    {
      if (sak.empty())
      {
        if (str[i] == '(')
          seen += 1;
        sak.push(str[i]);
      }
      else if (str[i] == ')')
      {
        if (seen != 0)
        {
          while (sak.top() != '(')
          {
            str2 += sak.top();
            str2.append(" ");
            sak.pop();
          }
          sak.pop();
          seen--;
        }
        else
          throw std::invalid_argument("No left bracket match!");
      }
      else
      {
        if (compareOperatorPriority(sak.top(), str[i]))
        {
          if (str[i] == '(')
          {
            seen++;
            sak.push(str[i]);
          }

          else
          {
            str2 += sak.top();
            str2.append(" ");
            sak.pop();
            sak.push(str[i]);
          }
        }
        else
        {
          sak.push(str[i]);
        }
      }
    }
  }
  while (!sak.empty())
  {
    if (seen != 0)
      throw invalid_argument("too many left barckets!");
    str2 += sak.top();
    str2.append(" ");
    sak.pop();
  }
  return str2;
}

int calculate(string &str)
{
  size_t pos1 = 0;
  size_t pos2 = 0;
  stack<int> b;
  while (pos2 != string::npos)
  {
    pos1 = str.find_first_not_of(' ', pos1);
    pos2 = str.find_first_of(' ', pos2);

    if (pos2 != string::npos)
    {
      string temp = str.substr(pos1, pos2 - pos1);
      if (temp.find_first_not_of("0123456789") == string::npos)
        b.push(stoi(temp));
      else
      {
        if (b.size() < 2)
          throw std::invalid_argument("too many symbols");
        int right = b.top();
        b.pop();
        int left = b.top();
        b.pop();
        int res;
        if (temp == "+")
          res = left + right;
        else if (temp == "*")
          res = left * right;
        else if (temp == "-")
          res = left - right;
        else if (temp == "/")
        {
          if (right == 0)
            throw std::invalid_argument("Divided by zero.");
          res = left / right;
        }

        b.push(res);
      }
      pos2 += 1;
      pos1 = pos2;
    }
  }
  return b.top();
}

int main()
{
  string str;
  string str2;
  str = "22*(1+2)-(3*4)/(2*1)";
  str2 = createBackSeq(str);
  cout << str2 << endl;
  cout << calculate(str2) << endl;

  str = "1+3*(2++5)";
  str2 = createBackSeq(str);
  cout << str2 << endl;
  cout << calculate(str2) << endl;	

  return 0;
}

测试:

input : 22*(1+2)-(3*4)/(2*1)

output :
22 1 2 + * 3 4 * 2 1 * / -
60
input : 1+3*(2+5)

output :
1 3 2 5 + * +
22
input : 1+3*((2+5)

output : terminate called after throwing an instance of 'std::invalid_argument' what(): too many left barckets!
input : 1+3*(2+5))

output : terminate called after throwing an instance of 'std::invalid_argument' what(): No left bracket match!
input : 1+3*(2+5)/0

output :
1 3 2 5 + * 0 / +
terminate called after throwing an instance of 'std::invalid_argument' what(): Divided by zero.
input : 1+3*(2++5)

output :
1 3 2 + 5 + * +
terminate called after throwing an instance of 'std::invalid_argument' what(): too many symbols.

参考:

  1. 《C++ Primer》
相关推荐
我们的五年12 分钟前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
做人不要太理性39 分钟前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19871 小时前
STL关联式容器之map
开发语言·c++
程序伍六七1 小时前
day16
开发语言·c++
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
火山口车神丶2 小时前
某车企ASW面试笔试题
c++·matlab
是阿建吖!2 小时前
【优选算法】二分查找
c++·算法
Ajiang28247353044 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
‘’林花谢了春红‘’9 小时前
C++ list (链表)容器
c++·链表·list