数据结构——02-算数表达式-栈-实验题目分享

一、实验题目

算数表达式计算:

设计算法根据用户输入的合法表达式计算结果并显示出来

表达式中的符号为+、-、*、/、(、)

表达式中数字为整数

二、实验环境

Windows 11

Visual Studio Code

(总体代码在最后)

三、实验过程

思路分析:

需要实现一个算法来解析和计算包含加法(+)、减法(-)、乘法(*)、除法(/)以及括号(( ))的合法整数表达式:

根据学过的树的知识,这个表达式可以有三种表达方式: ​ 前缀、中缀、后缀

前缀:将表达式变为前缀后,从右往左,每次从操作数栈取一个数,再取一个操作符,再取一个操作数,进行运算。

后缀:将表达式变为后缀后,从左往右,每次从操作数栈取一个数,再取一个操作符,再取一个操作数,进行运算。

中缀:虽然表达式写出来很适合人类观看,但是对计算机实现来说比较困难,每当遇见一个算术运算符就要看操作符栈是不是空的,如果是空的就直接放进去,如果不是空的就要比较优先级,如果优先级大就进去,如果小就要取出两个数字进行运算再放进去

举个例子:

img

img

img

img

1. 创建两个栈:一个用于存储操作数(数字),另一个用于存储操作符(+、-、*、/);

2. 从左到右扫描表达式:

如果遇到操作数,将其压入操作数栈。

如果遇到操作符:

        如果操作符栈为空,或者栈顶是左括号,直接将操作符压入操作符栈。

        如果当前操作符的优先级高于操作符栈栈顶的操作符,将当前操作符压入操作符栈。

        否则,从操作数栈中弹出一个操作数和操作符栈的栈顶操作符,执行相应的运算,并将结果压回操作数栈。然后将当前操作符压入操作符栈。

如果遇到左括号,将其压入操作符栈。

        如果遇到右括号,从操作数栈中弹出一个操作数和操作符栈中的操作符,执行运算,并将结果压回操作数栈。重复此过程直到遇到左括号,然后从操作符栈中弹出左括号。

3. 表达式扫描完毕后,如果操作符栈中仍有操作符,重复第二步的过程,直到操作符栈为空。

4. 最后,操作数栈中应该只剩下一个元素,即表达式的结果。

代码:

img

计算函数 (Calculate):这个函数负责执行基本的算术运算。它从数字栈中弹出两个数字,根据传入的运算符执行相应的运算,并将结果压入数字栈。

img

完整代码请见附件

测试结果:

img

四、结果分析

img

使用这两个结构体来实现数字栈和字符栈

img

压栈

img

主函数 (main):这是程序的入口点。它首先读取一个表达式,然后初始化数字栈和字符栈。接着,它遍历表达式中的每个字符,如果是数字,则将其转换为浮点数并入栈;如果是运算符,则根据运算符的优先级和栈内的运算符进行比较,然后决定是入栈还是执行计算。最后,当表达式中的所有字符都被处理完毕后,执行剩余的运算符,并将最终结果打印出来。

img

总体代码结构:

1. 输入处理:

  1. 从用户那里获取输入的表达式,并将其转换为字符数组或字符串。

  2. 编写一个函数来检查表达式的合法性,包括括号匹配和操作符的正确使用。

2. 表达式解析:

  1. 实现上述两个栈的逻辑。

  2. 编写一个循环来逐个字符处理表达式。

3. 计算结果:

  1. 根据两个栈的内容执行计算。

  2. 在遇到操作符时,从栈中弹出相应的操作数,执行运算,并压入结果。

4. 输出结果:

  1. 一旦表达式的所有部分都被处理完毕,操作数栈顶的元素就是最终结果。

  2. 显示结果给用户。

五、实验心得

在本次实验中,通过编写和测试一个简单的表达式求值器程序,加深对栈这一数据结构的理解,同时熟悉基本的算术运算和运算符优先级处理,我更加深入地理解了栈的工作原理以及如何利用栈来解决实际问题。

我将具体完成阶段分为三个:设计阶段:首先设计了两个栈结构,一个用于存储操作数(数字),另一个用于存储操作符(字符)。确定了每个栈的基本操作,包括初始化、入栈、出栈和获取栈顶元素。 编码阶段:接着,根据设计实现了主函数和栈操作函数。主函数负责读取表达式并逐个字符进行解析,根据运算符优先级和结合性规则,执行相应的入栈和计算操作。 测试阶段:在完成编码后,我进行了多轮测试,包括简单表达式的计算和错误输入的处理。

程序能够正确处理基本的算术表达式,并返回预期的结果。

学习总结:学习了栈的基本操作和在程序中的应用。 理解了运算符优先级和结合性的概念。 加强了对C语言中字符串处理和字符操作的理解。 意识到了代码测试的重要性,以及如何通过测试来发现并解决问题。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#define maximum 100000typedef struct//数字栈
{	float data[maximum];int top;
} number;typedef struct//字符栈
{	char data[maximum];int top;
} sign;void InitNumber(number *stack);//初始化数字栈
void GetTopNumber(number stack, float *e);//获取栈顶元素
void PushNumber(number *stack, float e);//进栈
void PopNumber(number *stack, float *e);//出栈void InitSign(sign *stack);
void GetTopSign(sign stack, char *e);
void PushSign(sign *stack, char e);
void PopSign(sign *stack, char *e);void Calculate(number *stack, char e);number Num;
sign sig;
char expression[maximum];int main()
{	gets(expression);int length;length = strlen(expression);int i;float en, n;char es;InitNumber(&Num);InitSign(&sig);for (i = 0; i < length; i++){	if (expression[i] >= '0' && expression[i] <= '9'){	n = expression[i] - '0'; //字符型转换为整型while (expression[i + 1] != '\0'){	if (expression[i + 1] >= '0' && expression[i + 1] <= '9'){	n = n * 10 + expression[i + 1] - '0';++i;}elsebreak;}PushNumber(&Num, n);}else if (expression[i] == '+' || expression[i] == '-' || expression[i] == '*' || expression[i] == '/'|| expression[i] == '^' || expression[i] == '(' || expression[i] == ')'){	switch (expression[i]){	case '+':if (sig.data[sig.top - 1] != '+' && sig.data[sig.top - 1] != '-' && sig.data[sig.top - 1] != '*'&& sig.data[sig.top - 1] != '/' && sig.data[sig.top - 1] != '^')//与栈顶元素的优先级相比较, 高于时入栈,此处判断是否入栈。PushSign(&sig, '+');else{	while (sig.top > 0 && sig.data[sig.top - 1] != '(') //如果栈不为空切不为左括号,则出栈{	PopSign(&sig, &es);Calculate(&Num, es);}PushSign(&sig, '+');}break;case '-':if (sig.data[sig.top - 1] != '+' && sig.data[sig.top - 1] != '-' && sig.data[sig.top - 1] != '*'&& sig.data[sig.top - 1] != '/' && sig.data[sig.top - 1] != '^')PushSign(&sig, '-');else{	while (sig.top > 0 && sig.data[sig.top - 1] != '('){	PopSign(&sig, &es);Calculate(&Num, es);}PushSign(&sig, '-');}break;case '*':if (sig.data[sig.top - 1] != '*' && sig.data[sig.top - 1] != '/' && sig.data[sig.top - 1] != '^')PushSign(&sig, '*');else{	while (sig.top > 0 && sig.data[sig.top - 1] != '('){	PopSign(&sig, &es);Calculate(&Num, es);}PushSign(&sig, '*');}break;case '/':if (sig.data[sig.top - 1] != '*' && sig.data[sig.top - 1] != '/' && sig.data[sig.top - 1] != '^')PushSign(&sig, '/');else{	while (sig.top > 0 && sig.data[sig.top - 1] != '('){	PopSign(&sig, &es);Calculate(&Num, es);}PushSign(&sig, '/');}break;case '^':if (sig.data[sig.top - 1] != '^')PushSign(&sig, '^');else{	while (sig.top > 0 && sig.data[sig.top - 1] != '('){	PopSign(&sig, &es);Calculate(&Num, es);}PushSign(&sig, '^');}case '(':PushSign(&sig, '(');break;case ')':while (sig.data[sig.top - 1] != '('){	PopSign(&sig, &es);Calculate(&Num, es);}PopSign(&sig, &es);}}}while (sig.top > 0){	PopSign(&sig, &es);Calculate(&Num, es);}GetTopNumber(Num, &en);printf("%.0f\n", en);return 0;
}void InitNumber(number *stack)
{	stack->top = 0;
}void GetTopNumber(number stack, float *e)
{	if (stack.top == 0)return;else *e = stack.data[stack.top - 1];
}void PushNumber(number *stack, float e)
{	if (stack->top >= maximum)return;elsestack->data[stack->top++] = e;
}void PopNumber(number *stack, float *e)
{	if (stack->top == 0)return;else *e = stack->data[--stack->top];
}void InitSign(sign *stack)
{	stack->top = 0;
}void GetTopSign(sign stack, char *e)
{	if (stack.top == 0)return;else *e = stack.data[stack.top - 1];
}void PushSign(sign *stack, char e)
{	if (stack->top >= maximum)return;//栈满else{	stack->data[stack->top] = e;stack->top++;}
}void PopSign(sign *stack, char *e)
{	if (stack->top == 0)return;else *e = stack->data[--stack->top];
}void Calculate(number *stack, char e)// 计算结果
{	float num1, num2, result;PopNumber(stack, &num2);PopNumber(stack, &num1);switch (e){	case '+':result = num1 + num2;PushNumber(stack, result);break;case '-':result = num1 - num2;PushNumber(stack, result);break;case '*':result = num1 * num2;PushNumber(stack, result);break;case '/':if (num2 == 0)printf("表达式错误!");else{	result = num1 / num2;PushNumber(stack, result);break;}case '^':result = pow(num1, num2);PushNumber(stack, result);break;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/26627.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文笔记:ATime-Aware Trajectory Embedding Model for Next-Location Recommendation

Knowledge and Information Systems, 2018 1 intro 1.1 背景 随着基于位置的社交网络&#xff08;LBSNs&#xff09;&#xff0c;如Foursquare和Facebook Places的日益流行&#xff0c;大量用户签到数据变得可用 这些大量签到数据的可用性带来了许多有用的应用&#xff0c;以…

kotlin类型检测与类型转换

一、is与!is操作符 1、使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型。 fun main() {var a "1"if(a is String) {println("a是字符串类型:${a.length}")}// 或val b a is Stringprintln(b) } 二、"不安全的"转换操作符…

搜索是门艺术,大神都是这样找资源

以下所有资源均可在星云导航找到&#xff0c;网站地址&#xff1a;https://www.xygalaxy.com/ 浏览器搜索高级用法 1、排除干扰&#xff0c;指定关键词 1.1、排除指定关键字 格式&#xff1a;关键字1 -关键字2比如搜索&#xff1a;星云导航&#xff0c;不想要CSDN的内容 星…

【全开源】快递寄件小程序源码(FastAdmin+ThinkPHP+原生微信小程序)

&#x1f4e6;快递寄件小程序&#xff1a;轻松寄送&#xff0c;便捷生活 &#x1f69a;一、引言&#xff1a;告别繁琐&#xff0c;让寄件更简单 在繁忙的生活中&#xff0c;寄送快递往往成为我们的一大难题。传统的寄件方式需要前往快递公司网点&#xff0c;填写繁琐的寄件信…

单目标应用:基于蛇鹫优化算法SBOA的微电网优化(MATLAB代码)

一、微电网模型介绍 微电网多目标优化调度模型简介_vmgpqv-CSDN博客 参考文献&#xff1a; [1]李兴莘,张靖,何宇,等.基于改进粒子群算法的微电网多目标优化调度[J].电力科学与工程, 2021, 37(3):7 二、蛇鹫优化算法求解微电网 2.1算法简介 蛇鹫优化算法&#xff08;Secre…

基于python多光谱遥感数据处理、图像分类、定量评估及机器学习

原文链接&#xff1a;基于python多光谱遥感数据处理、图像分类、定量评估及机器学习 普通数码相机记录了红、绿、蓝三种波长的光&#xff0c;多光谱成像技术除了记录这三种波长光之外&#xff0c;还可以记录其他波长&#xff08;例如&#xff1a;近红外、热红外等&#xff09;光…

企业中的绩效管理

背景 企业中为何需要绩效管理&#xff0c;企业绩效管理为何比较难&#xff0c;这在企业管理中是非常难&#xff0c;同样也是非常有价值的命题&#xff0c;那么首先应该对这个命题有清晰的认知&#xff0c;特别是要想明白为何企业需要绩效管理&#xff0c;应该先明白企业。 企…

Uniapp实现页面滚动Tab吸顶,点击tab内容滚动到对应tab内容位置

1.template结构 <view class"content-tabs-box"><view class"content-tabs" :class"{is-fixed: isTabFixed}"><viewv-for"(item, index) in detailTabs" :key"index" class"tab" :class"{act…

【git使用四】git分支理解与操作(详解)

目录 &#xff08;1&#xff09;理解git分支 主分支&#xff08;主线&#xff09; 功能分支 主线和分支关系 将分支合并到主分支 快速合并 非快速合并 git代码管理流程 &#xff08;2&#xff09;理解git提交对象 提交对象与commitID Git如何保存数据 示例讲解 &a…

lnmp的介绍与源码部署以及 |什么是正向、反向、透明代理 | 常见的集群有哪些

lnmp 文章目录 lnmp1.LNMP是什么2. lnmp简介3.系统特点4.优点5.lnmp部署5.1 nginx安装5.2 mysql安装5.3 php安装5.4配置nginx服务处理php 6.扩展知识点1.什么是集群2.常见的集群有哪些集群的分类1、高可用集群2、负载均衡集群3、分布式计算集群4、高性能集群(High Performance …

嵌入式常用调试方法

目录 调试工具 日志打印 1. Debug日志打印 2. RTT日志打印 3. 串口日志打印 总结 嵌入式系统的调试是一个复杂且关键的过程&#xff0c;涉及多种工具和技术的综合应用。以下是对嵌入式常见调试工具、日志打印方式的全面报告&#xff0c;包括Debug、RTT&#xff08;Real-T…

重生奇迹mu魔法师介绍

魔法师擅长&#xff1a;远距作战、攻击&辅助魔法使用 转职&#xff1a;魔导师&#xff08;2转&#xff09;&#xff0c;神导师&#xff08;3转&#xff09; 魔法师可以通过多样的魔法&#xff0c;展现华丽的效果和强大的实力。成长初期因为体力少&#xff0c;经常受到死亡…

线程池前置知识

并发和并行 并发是指在单核CPU上&#xff0c;多个线程占用不同的CPU时间片。线程在物理上还是串行执行的&#xff0c;但是由于每个线程占用的CPU时间片非常短&#xff08;比如10ms&#xff09;&#xff0c;看起来就像是多个线程都在共同执行一样&#xff0c;这样的场景称作并发…

Python私教张大鹏 Vue3整合AntDesignVue之Cascader 级联选择

何时使用 需要从一组相关联的数据集合进行选择&#xff0c;例如省市区&#xff0c;公司层级&#xff0c;事物分类等。 从一个较大的数据集合中进行选择时&#xff0c;用多级分类进行分隔&#xff0c;方便选择。 比起 Select 组件&#xff0c;可以在同一个浮层中完成选择&#…

足底筋膜炎怎样才能彻底治愈

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

windows中安装libreOffice最新版本24.2.4

windows中安装libreOffice最新版本24.2.4 一. 介绍二. 安装过程2.1 下载 LibreOffice2.2 安装过程2.3 页面展示 三. 参考文档 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一. 介…

易基因:【表观遗传学基础】如何研究DNA甲基化

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 表观遗传学近几年取得的一系列研究进展&#xff0c;确实吸引着越来越多的关注&#xff01;为了帮大伙儿梳理一下表观遗传学的基本概念和研究方法&#xff0c;小编打算开一个系列专题&…

VBA实现关闭Excel自动计算,关闭屏幕刷新

Excel代码提速神器 涉及到提取表格大量数据操作&#xff0c;复制粘贴多个单元格时&#xff0c;尽量避免一个个单元格提取&#xff0c;或者一行行一列列提取数值&#xff0c;设计大量IO流操作非常浪费时间。尽量找出数据之间的规律&#xff0c;批量选中复制粘贴&#xff0c;找到…

第五十一天 | 1143.最长公共子序列

题目&#xff1a;1143.最长公共子序列718.最长重复子数组的区别是&#xff0c;子序列不要求连续&#xff0c;子数组要求连续。这一差异体现在dp数组含义和递推公式中&#xff0c;本题是子序列&#xff0c;那就要考虑上nums1[i - 1] ! nums2[j - 1]的情况。 本道题与 1.dp数组…

inBuilder 低代码平台新特性推荐 - 第二十一期

今天给大家带来的是inBuilder低代码平台新特性推荐第二十一期——inBuilder单点登录链接生成器 一、场景介绍 在系统间的集成对接过程中&#xff0c;普遍存在通过单点登录链接进入系统的场景。比如通过单点登录链接进入流程工作台&#xff0c;进入用户管理等功能。inBuilder单…