四则计算机实现(C++)(堆栈的应用)

简介: 四则计算机实现(C++)(堆栈的应用)

算法要求:

  1. 输入一个数学表达式(假定表达式输入格式合法),计算表达式结果并输出。
  2. 数学表达式由单个数字和运算符“+”、“-”、“*”、“/”、“(、) ”构成,例如 2 + 3 * ( 4 + 5 ) - 6 / 4。
  3. 变量、输出采用整数,只舍不入。

图解算法思想:

1、图中1、2、3、4~~表示操作的前后顺序

2、图中橙色栈用来处理数字,黄色用来处理运算符。

3、本图实际上将中缀转后缀、后缀求值两步整合在一起  

最后一步执行:取出‘-’,然后43-6=37,作为最后结果。

 

程序思想流程图:

 

代码如下:

【实验全部代码】
#include <iostream>
#include <string>
using namespace std;
// 写一个栈的模板函数,因为下面需要用到 int 和 char 两种 stack 类型,且方法一样
template <class T>
class Stack {
private:
    T data[1001];
    int size; // 同时承担 top 的作用
public:
    Stack() {
        size = 0;
    }
    ~Stack() {
        size = 0;
    }
    T pop() {//出栈
        size--;
        return data[size];
    }
    void push(T a) {//入栈
        data[size++] = a;
    }
    T front() {//返回栈顶元素
        return data[size - 1];
    }
    void clear() {//清除栈中元素,非物理清除,仅逻辑清除
        size = 0;
    }
    bool empty() {//判空
        return (size == 0);
    }
};
// 中序转后序函数
string inToSuffix(string s) {
    string result = "";
    int size = s.size();
    Stack<char> a;
    for (int i = 0; i < size; i++) {
//对括号的处理
        if (s[i] == '(') {
            a.push(s[i]);
        } else if (s[i] == ')') {
            if (!a.empty()) {
                char t = a.pop();
                while (t != '(' && !a.empty()) {
                    result.push_back(t);
                    t = a.pop();
                }
            }
//加减乘除的处理
        } else if (s[i] == '+' || s[i] == '-') { // 加减的等级是最低的
            while (!a.empty()) {
                if (a.front() == '(') {
                    break;
                } else { // 加减和乘除的处理方式一样,都是弹出
                    result.push_back(a.pop());
                }
            }
            a.push(s[i]);
        } else if (s[i] == '*' || s[i] == '/') {
            while (!a.empty()) {
                if (a.front() == '(') {
                    break;
                } else if (a.front() == '*' || a.front() == '/') { // 仅仅乘除被弹出,加减留在里面
                    result.push_back(a.pop());
                } else
                    break; // 如果遇到加减,则要直接 break,否则死循环
            }
            a.push(s[i]);
//数字的处理
        } else if (s[i] >= '0' && s[i] <= '9') {
            result.push_back(s[i]);
        } else {
            cout << "存在非法输入" << endl;
            break;
        }
    }
    while (!a.empty()) { // 最后要把栈中所有东西一一输出
        result.push_back(a.pop());
    }
    return result;
}
int suffix_print(string s) { // 后缀表达式核心就在于运算顺序,所以中缀中的括号在后缀中已经转化为数字和运算的前后顺序
    Stack<int> a;
    int size = s.size();
    for (int i = 0; i < size; i++) {
        if (s[i] >= '0' && s[i] <= '9')
            a.push(s[i] - '0');
        else {
            int s2 = a.pop();
            int s1 = a.pop();
            if (s[i] == '*') {
                a.push(s1 * s2);
            } else if (s[i] == '+') {
                a.push(s1 + s2);
            } else if (s[i] == '/') {
                a.push(s1 / s2);
            } else {
                a.push(s1 - s2);
            }
        }
    }
    return a.front();
}
int main() {
    cout << "Input" << endl;
    string input;
    cin >> input;
    cout << "Output" << endl;
    string inpute1 = inToSuffix(input);
    cout << "=" << suffix_print(inpute1) << endl;
    cout << "End";
    return 0;
}

感悟与算法分析:

本题是实现计算器的制作。可以分为三个子问题:括号作用在数据结构中的实现、如何将中缀表达式化为后缀表达式、如何将后缀表达式的值计算出来

针对

问题一:对于一个表达式,我们采用栈的方式去存储。那么如何用栈来处理括号问题呢?

  1. 遇到括号则判断是否是哪一类型括号
  2. 如果是左括号则直接压入栈,后续将括号内的符号一一压入,期间这些符号也可以弹出,但是左括号一直不弹出。直到遇到右括号,则左括号上面以及左括号本身都要一并弹出。但是左括号并不输出、同时右括号并不压入栈。
  3. 如果右括号遇到但是栈中所有元素都弹出也没有左括号则报错误。若是左括号到程序最后也没有弹出则报错误

问题二:如何将中缀表达式转化为后缀表达式只要遵循下面这几个要求即可。

  1. 利用栈结构来处理
  2. 遇到1~9的数字直接printf打印输出,栈仅仅记录运算符号。
  3. 遇到括号则分为左右两种括号按照问题一的要求来处理
  4. 遇到+-*/运算符则要先把栈中优先级等于或小于该运算符的一一弹出,然后把该运算符本身压入栈中。

所以本问题可以利用多次的if判断语句,将问题分为这几种情况分别按照要求去处理

问题三:后缀表达式的求值也同样分为以下几个步骤来处理即可。

  1. 同样需要栈,但是栈此时存放的是数字
  2. 遇到数字则直接压入栈
  3. 遇到一个运算符则取出栈顶的两个元素,按照先输出的在左边、后输出的在右边与该运算符进行计算,并将运算结果重新压回栈中
  4. 在后缀表达式结束后,将栈中的元素取出来即为最后的答案

综上来说本题考察的主要是波兰表达式和逆波兰表达式的转化,以及逆波兰表达式的计算。而这些计算借助的数据结构就是栈。程序在书写的过程中最需要注意的就是if、elseif的分类处理。有一些类处理中需要用break来退出,否则会让程序进入死循环。其他一些注意点都在程序注释中标明。

仅供参考,一定不要直接复制!!!查重很严的!!!

相关文章
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
423 15
|
9月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
331 11
|
存储 安全 C++
C++中的引用和指针:区别与应用
引用和指针在C++中都有其独特的优势和应用场景。引用更适合简洁、安全的代码,而指针提供了更大的灵活性和动态内存管理的能力。在实际编程中,根据需求选择适当的类型,能够编写出高效、可维护的代码。理解并正确使用这两种类型,是掌握C++编程的关键一步。
464 1
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
669 12
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
540 5
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
643 5
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
375 2
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
375 4
|
存储 算法 C++
C++ STL应用宝典:高效处理数据的艺术与实战技巧大揭秘!
【8月更文挑战第22天】C++ STL(标准模板库)是一组高效的数据结构与算法集合,极大提升编程效率与代码可读性。它包括容器、迭代器、算法等组件。例如,统计文本中单词频率可用`std::map`和`std::ifstream`实现;对数据排序及找极值则可通过`std::vector`结合`std::sort`、`std::min/max_element`完成;而快速查找字符串则适合使用`std::set`配合其内置的`find`方法。这些示例展示了STL的强大功能,有助于编写简洁高效的代码。
401 2
|
C++ 存储 Java
C++多线程相关应用
C++多线程相关应用
322 0
C++多线程相关应用