📜  用C C++程序制作一个简单的计算器(1)

📅  最后修改于: 2023-12-03 14:56:17.784000             🧑  作者: Mango

用C/C++程序制作一个简单的计算器

本文将介绍如何用C/C++编写一个简单的计算器程序。

实现思路

计算器程序需要具备以下功能:

  • 能够读入用户输入的算式;
  • 能够对算式进行计算;
  • 能够输出计算结果。

我们可以通过读取用户输入的算式,将其转换为逆波兰表达式,然后再对逆波兰表达式进行计算,得到最终的结果。在这个过程中,我们需要用到以下两个数据结构:

  • 栈:用于转换算式为逆波兰表达式;
  • 队列:用于存储逆波兰表达式。

实现思路如下:

  1. 从终端读取用户输入的算式;
  2. 利用栈将中缀表达式转换为后缀表达式(即逆波兰表达式);
  3. 利用队列存储逆波兰表达式;
  4. 利用栈对队列中的逆波兰表达式进行计算,得到结果;
  5. 输出计算结果。
代码实现

代码实现分为如下几个部分:

定义栈和队列的数据结构

C++ 中可以使用 STL 中的 stack 和 queue 实现栈和队列的数据结构。

#include<stack>
#include<queue>
using namespace std;
stack<double> numStack; // 存储数字的栈
queue<string> rpnQueue; // 存储逆波兰表达式的队列
将中缀表达式转换为逆波兰表达式

将中缀表达式转换为逆波兰表达式需要遍历中缀表达式,将数字和运算符按照一定的规则压入栈中。这里我们使用的是经典的双栈算法,即一个存储运算符的栈,一个存储数字和括号的栈。

具体实现见以下代码:

// 运算符优先级表
map<char, int> priority = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0}};
// 将中缀表达式转换为逆波兰表达式
void inFixToPostFix(string inFixExpression) {
    numStack = stack<double>(); // 清空之前计算的结果
    rpnQueue = queue<string>(); // 清空队列
    stack<char> operStack; // 用于存储运算符的栈
    int i = 0;
    while (i < inFixExpression.length()) {
        if (inFixExpression[i] >= '0' && inFixExpression[i] <= '9' || inFixExpression[i] == '.') {
            // 如果是数字,则直接加入队列
            string num = "";
            while (i < inFixExpression.length() && (inFixExpression[i] >= '0' && inFixExpression[i] <= '9' || inFixExpression[i] == '.')) {
                num += inFixExpression[i];
                i++;
            }
            rpnQueue.push(num);
        } else {
            // 如果是运算符,则判断优先级,并将栈中的运算符加入队列
            if (operStack.empty() || priority[operStack.top()] < priority[inFixExpression[i]]) {
                operStack.push(inFixExpression[i]);
                i++;
            } else if (inFixExpression[i] == ')') {
                // 如果是右括号,则将栈中的运算符取出并加入队列
                while (operStack.top() != '(') {
                    string oper = "";
                    oper += operStack.top();
                    rpnQueue.push(oper);
                    operStack.pop();
                }
                operStack.pop(); // 将左括号出栈
                i++;
            } else {
                // 如果是运算符,且栈中运算符的优先级 >= 当前运算符的优先级,则将栈中的运算符取出并加入队列
                while (!operStack.empty() && priority[operStack.top()] >= priority[inFixExpression[i]]) {
                    string oper = "";
                    oper += operStack.top();
                    rpnQueue.push(oper);
                    operStack.pop();
                }
                operStack.push(inFixExpression[i]);
                i++;
            }
        }
    }
    // 将栈中的剩余运算符加入队列
    while (!operStack.empty()) {
        string oper = "";
        oper += operStack.top();
        rpnQueue.push(oper);
        operStack.pop();
    }
}
对逆波兰表达式进行计算

对逆波兰表达式进行计算需要将数字压入栈中,并在遇到运算符时弹出栈中两个数字进行计算,再将结果压入栈中。

具体实现如下:

// 对逆波兰表达式进行计算
double calculate() {
    while (!rpnQueue.empty()) {
        string exp = rpnQueue.front();
        rpnQueue.pop();
        if (exp == "+") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 + num1);
        } else if (exp == "-") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 - num1);
        } else if (exp == "*") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 * num1);
        } else if (exp == "/") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 / num1);
        } else {
            double num = stod(exp);
            numStack.push(num);
        }
    }
    return numStack.top();
}
完整代码
#include<iostream>
#include<stack>
#include<queue>
#include<map>
using namespace std;
stack<double> numStack; // 存储数字的栈
queue<string> rpnQueue; // 存储逆波兰表达式的队列
// 运算符优先级表
map<char, int> priority = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}, {'(', 0}};
// 将中缀表达式转换为逆波兰表达式
void inFixToPostFix(string inFixExpression) {
    numStack = stack<double>(); // 清空之前计算的结果
    rpnQueue = queue<string>(); // 清空队列
    stack<char> operStack; // 用于存储运算符的栈
    int i = 0;
    while (i < inFixExpression.length()) {
        if (inFixExpression[i] >= '0' && inFixExpression[i] <= '9' || inFixExpression[i] == '.') {
            // 如果是数字,则直接加入队列
            string num = "";
            while (i < inFixExpression.length() && (inFixExpression[i] >= '0' && inFixExpression[i] <= '9' || inFixExpression[i] == '.')) {
                num += inFixExpression[i];
                i++;
            }
            rpnQueue.push(num);
        } else {
            // 如果是运算符,则判断优先级,并将栈中的运算符加入队列
            if (operStack.empty() || priority[operStack.top()] < priority[inFixExpression[i]]) {
                operStack.push(inFixExpression[i]);
                i++;
            } else if (inFixExpression[i] == ')') {
                // 如果是右括号,则将栈中的运算符取出并加入队列
                while (operStack.top() != '(') {
                    string oper = "";
                    oper += operStack.top();
                    rpnQueue.push(oper);
                    operStack.pop();
                }
                operStack.pop(); // 将左括号出栈
                i++;
            } else {
                // 如果是运算符,且栈中运算符的优先级 >= 当前运算符的优先级,则将栈中的运算符取出并加入队列
                while (!operStack.empty() && priority[operStack.top()] >= priority[inFixExpression[i]]) {
                    string oper = "";
                    oper += operStack.top();
                    rpnQueue.push(oper);
                    operStack.pop();
                }
                operStack.push(inFixExpression[i]);
                i++;
            }
        }
    }
    // 将栈中的剩余运算符加入队列
    while (!operStack.empty()) {
        string oper = "";
        oper += operStack.top();
        rpnQueue.push(oper);
        operStack.pop();
    }
}
// 对逆波兰表达式进行计算
double calculate() {
    while (!rpnQueue.empty()) {
        string exp = rpnQueue.front();
        rpnQueue.pop();
        if (exp == "+") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 + num1);
        } else if (exp == "-") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 - num1);
        } else if (exp == "*") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 * num1);
        } else if (exp == "/") {
            double num1 = numStack.top();
            numStack.pop();
            double num2 = numStack.top();
            numStack.pop();
            numStack.push(num2 / num1);
        } else {
            double num = stod(exp);
            numStack.push(num);
        }
    }
    return numStack.top();
}
// 主函数
int main() {
    string inFixExpression;
    cout << "请输入要计算的算式:" << endl;
    cin >> inFixExpression;
    inFixToPostFix(inFixExpression);
    double result = calculate();
    cout << "计算结果为:" << result << endl;
    return 0;
}