草庐IT

数据结构03:设计并实现一个整型表达式计算器

小微不想学高数 2023-04-08 原文
  • 实验目的和要求

熟悉并使用顺序栈。

  1. 要求计算方法根据PPT例题求解方法进行。
  2. 只处理整型算术运算表达式,即运算符至少包含+-*/()。
  3. 其中,要求抽象出栈结构进行独立实现。
  4. 其它要求同课后作业-01要求。

二、实验环境

硬件环境:微型计算机

操作系统:Windows 11

语言:C++
软件环境:IDEA Microsoft Visual Studio 2019   

三、实验内容

设计并实现一个整型表达式计算器,只处理整型算术运算表达式,即运算符至少包含+-*/(),其中,要求抽象出栈结构进行独立实现。

四、实验过程

4.1 任务定义和问题分析

         需要实现整型算术表达式的运算,运用抽象栈的结构。

    需要考虑表达式的输入和使用,以及元素类型转换的问题。

    需要考虑运算符优先级设置的问题。

    需要判断栈当前的状态,并返回相应的结果。

4.2 概要设计(数据结构)

 

  1. 读入整形表达式并对其中的元素进行拆分

本次实验的数据采用键入的方式,将键入的数据存入string类中,string类不必担心内存是否足够、键入字符串长度,而且作为一个类出现,他集成的操作函数足以完成大多数情况下的需要,它可以看成是C++的基本数据类型。所以在头文件加入<string>,用类自带的.size()函数得到输入表达式的长度。string定义的类型可以直接使用下标操作符[]像数组一样被调用,方便了元素性质的判断和类型的转换。

  1. 判断元素的类型

本次实验通过isp()和isr()两个函数,比较元素的ASCII码实现元素类型的判断。

  1. 栈的设计和应用

(1)几个运算的条件可能有不成立的情况,因此,需要给予明确的反映。

(2)设立运算是否正常的类型errorcode,正常时返回success, 否则返回错误类型,如overflow, underflow等。enum errorcode {success, overflow, underflow}; 可以将这几个函数的类型设置为errorcode;。

(3)如果需要返回其他的值,可以作为参数来返回。

(4)取栈顶元素的运算功能描述: 如果栈不空,则取出栈顶元素到参数x中,然后返回success。否则,返回downflow。 对应的运算函数为:errorcode get_top(elementtype &x) const。

(5)入栈的运算功能描述: 如果栈不满,则将元素入栈,并返回success。 否则,返回overflow。对应的运算函数为:errorcode push(const elementtype x)。

(6)出栈的运算功能描述: 如果栈不空,删除当前栈顶的元素,并返回success。 否则,返回underflow。对应的运算函数为:errorcode pop()。

(7)使用模板类,拓宽类的适用范围,减少程序冗余,是代码具有高效性。

  1. 操作符优先级的设置和比较及其运算

(1)在整个算数表达式的前后加上“#”,作为优先级最低的运算符,等级为-1,方便与其他运算符入栈和出栈的比较。

(2)赋予不同的运算符不同的等级,其中“(”、“)”等级为0,“+”、“-”等级为1,“*”、“/”等级为2。

(3)进入判断程序比较与栈顶的运算符的优先级,同时判断是否是左右括号,左右括号是否见面。

(4)达到计算要求后取出栈顶的数据,并将栈顶下移一层,再次去除栈顶的数据,依据运算符号进行相应的运算。

4.3 详细设计

 实现数据类型的判断

 

 实现最后数据的计算

 

 数据类型转换

 

 对于操作数的操作

 

 

对于运算符的操作

 

栈的实现

五、测试及结果分析

5.1 实验数据

         1+1

         (1+1)

34+26*18-66/3

37+4*(2+3*17-21/3)*6-(4+8)*12

9*(12*5-4/2)*(33-36/9)+10/5-14*(3*8/6)

5.2 结果及分析

                           1+1=2

 

                             

                                 (1+1)=2

 

                             

                                 34+26*18-66/3=480

 

                             

                 

 

37+4*(2+3*17-21/3)*6-(4+8)*12=997

                             

                             

 

                                                     9*(12*5-4/2)*(33-36/9)+10/5-14*(3*8/6)=15084

六、实验收获

         1. 一个编译器用不下去的时候要学会换一个,VS的界面显然更好看一点。

         2. 当运算结果挑战了你的数学认知的时候千万不要怀疑,那绝对不会是数学的问题。

         3. 在开始编写程序之前要做好流程给的设计,理清逻辑关系,在实际编程中才不会把任务和数据混淆。

         4. 不要在一条路上走到黑,必要的搜索和思路调整也许能把程序拖出困境。

         5. 时刻注意数组的下标!

七、参考文献

         一些CSDN的文章😊

八、附录(源代码)

#include <iostream>
#include <stack>
#include <string>
using namespace std; 
enum errorcode {
    success, overflow, underflow
};
template<class T>
class Stack {
public:
    Stack() {
        count = 0;
    }
    bool empty()const {
        if (count == 0) return true;
        else return false;
    }
    bool full()const {
        if (count == 50) return true;
        else return false;
    }
    template<class T>
    errorcode get_top(T& x)const {
        if (empty()) return underflow;
        else {
            x = data[count - 1];
            return success;
        }
    }
    template<class T>
    errorcode push(const T x) {
        if (full()) return overflow;
        data[count] = x;
        count++;
        return success;
    }
    errorcode pop() {
        if (empty()) return underflow;
        count--;
        return success;
    }
private:
    int count;
    T data[50];
};

bool isp(char n) {
    if (n >= '0' && n <= '9') return 1;
    return 0;
}

int isr(char n) {
    if (n == '+' || n == '-')
        return 1;
    else if (n == '*' || n == '/')
        return 2;
    else if (n == '(' || n == ')')
        return 0;
    else
        return -1;
}

int jisuan(char x, Stack<int>& num) {
    int a, b;
    int c = 0;
    if (x == '+') {
        num.get_top(a);
        num.pop();
        num.get_top(b);
        num.pop();
        c = a + b;
    }
    else if (x == '-') {
        num.get_top(a);
        num.pop();
        num.get_top(b);
        num.pop();
        c = b - a;
    }
    else if (x == '*') {
        num.get_top(a);
        num.pop();
        num.get_top(b);
        num.pop();
        c = a * b;
    }
    else if (x == '/') {
        num.get_top(a);
        num.pop();
        num.get_top(b);
        num.pop();
        c = b / a;
    }
    return c;
}

int change(char x) {
    int y;
    y = x - 48;
    return y;
}

int Panduan(string a) {
    Stack<int> s1;
    Stack<char> s2;
    a += '#';
    s2.push('#');
    for (int i = 0; i <= a.size(); i++) {
        if (isp(a[i])) {
            int sum = change(a[i]);
            while (isp(a[i+1])) {
                i++;
                sum = sum * 10 + change(a[i]);
            }
            s1.push(sum);
        }
        else {
            int k = 1;
            char x, y;
            s2.get_top(x);
            while (k) {
                if (isr(a[i]) > isr(x) || a[i] == '(') {
                    s2.push(a[i]);
                    break;
                }
                else {
                    if (isr(a[i]) == isr(x) && isr(a[i]) == 0 || isr(a[i]) == isr(x) && isr(a[i]) == -1) {
                        s2.pop();
                        break;
                    }
                    else {
                        s1.push(jisuan(x, s1));
                        s2.pop();
                        s2.get_top(y);
                        x = y;
                    }
                }
            }
        }
    }
    int p;
    s1.get_top(p);
    return p;
}

int main() {
    string a;
    cin >> a;
    cout << Panduan(a) << endl;
    return 0;
}

有关数据结构03:设计并实现一个整型表达式计算器的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  7. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

随机推荐