2024.4.15 学习数理结构“栈”后的四则运算
使用栈的四则运算
1.题目描述
用顺序栈和算符优先法求解表达式的值
2.任务定义和问题分析
四则运算基本运要通过算法优先级和后缀表达式的思想完成,应当由以下功能:
(1)可以先求解后缀表达式。然后再求值,也可以一并完成。
(2)表达式中的运算为加、减、乘、除四种,包括括号,参与运算的数字为个位数。
(3)要考虑除法运算除数为零的特殊情况,有相应的处理措施。
(4)能检测括号不匹配的情况。
(5)建立操作符栈和操作数栈,编写相应的进栈和出栈函数。
(6)要有任务分解逐步求精的意识,合理划分子函数实现单个功能。
(7)可以进行多次表达式的计算,而不是运算一次就结束。
(7)操作数可以为多位整数,或者小数。例如123(2.3+89.5)。
(8)可增加阶乘运算,例如3!+42/(1-5)。
(9)可增加指数运算,例如4*2/(1-5)^2。
分析问题:分析四则运算需要用顺序栈来完成计算。因为我们只在一端输入输出,使用顺序栈使用数组下标进行进栈出栈操作更方便快捷,且由于一次性分配了足够的内存,时间处理上更快。而为防止栈的溢出,我使用动态分配的顺序栈。各具体功能设计为子函数,方便调试和复用,同时程序结构清晰易读。
简单的逻辑结构:定义一个char类型的字符组作为字符栈,一个int类型的数组作为数字栈。各子函数中,根据具体情形进行异常处理并给出提示。(像输入错误格式的算术式时会给出恰当的提示)。
3.数据结构的选择和概要设计
一.为了实现上述程序功能,首先定义存储的字符的字符栈以及数字栈。
二.系统中的子函数及功能要求
程序中共有14个子函数,分别为:
①边将算术式转为后缀表达式边计算的函数option()
②寻找大数小数的函数find()
③进数字栈的函数input_number()
④判断数字栈是否满了的函数Fulli()
⑤判断字符栈是否满并存入一个字符的函数Storage()
⑥判断字符栈是否满的函数 fullc()
⑦将一个字符存入字符栈input_char()
⑧使用弹出的运算符的函数Operation_And_Storage()
⑨将一个数字出栈的函数output_number()
⑩进行实际运算的函数shuan()
⑪弹出字符的函数output_number()
⑫计算阶乘的函数jie()
⑬为字符栈增添空间的函数addstackc()
⑭为数字栈增添空间Addstacki()
各子函数具体介绍如下:
(1)double option(char a[],char_stack b,int_stack c)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或 计算的值
④功 能:边将算术式转为后缀表达式边计算
(2)double find(char a[],int *r,int i)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或找到的数
④功 能:使四则运算可以计算小数和大于10的自然数
(3)void input_number(double a,int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:将一个数存入数字栈
(4)void fulli(int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断数字栈是否满了
(5)void Storage(char a,char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断字符栈是否满并存入一个字符
(6)void fullc(char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:判断字符栈是否满
(7)Void input_char(a,b)
①输 入:无
②输 出:无
③返回值:无
④功 能:将一个字符存入字符栈
(8)double Operation_And_Storage(char_stack b,int_stack c)
①输 入:无
②输 出:无
③返回值:输入错误的提示ERROR 或 1
④功 能:弹出两个数字栈,弹出一个字符栈,根据字符栈计算,就计算结果存入数字栈
(9)double output_number(int_stack c)
①输 入:无
②输 出:无
③返回值:出栈的数字
④功 能:将数字栈出一个栈
(10)double shuan(double a,double b,char c)
①输 入:无
②输 出:无
③返回值:计算的结果 或 输入错误的提示ERROR
④功 能:实际计算操作
(11)char out_char(char_stack b)
①输 入:无
②输 出:无
③返回值:弹出的字符
④功 能:将一个字符弹出字符栈
(12)double jie(int a)
①输 入:无
②输 出:无
③返回值:阶乘的值
④功 能:计算阶乘
(13)void addstackc(char_stack b)
①输 入:无
②输 出:无
③返回值:无
④功 能:为字符栈增添空间
(14)void addstacki(int_stack c)
①输 入:无
②输 出:无
③返回值:无
④功 能:为数字栈增添空间
三.主程序及各程序模块(函数)之间的层次(调用)关系
4.详细设计
(一)double option(char a[],char_stack b,int_stack c)
我将遇到的字符分为几大类,分别是数字,(,),+或-,*或/,!,^.7种情况。并根据算术优先顺序对每大类进行分类讨论。由于分类多但每个类别进行的操作都简单不适合用文字赘述,就看我的逻辑框架。
逻辑框架:
流程图:
代码与注释:
(二)double find(char a[],int (*)r,int i)(由于博客园不显示我的指针符*,所以我只好加了个括号框起来,你自己写不要框)
通过循环判断大数或小数是多少。一直取a[i]的下一个字符,如果是数字就让本来的数字10加上该数字成为新的本来数字,直到下一个不是数字。如果这个不是数字的字符恰好是“.”小数点,就一直取a[i]的下一个字符,让本来数字加上该数字pow(10,-w),w为小数点后的几位。直到下次不是数字。
5.调试分析
问题(1):
问题概述:一开始我的主要逻辑程序全部写在一起,像缠绕在一起的数据线,杂乱无章。当我想要完成进阶任务时,我发现自己的程序不具有可维护性和提升性。
解决过程:我先画了个简单的思维导图,将重复的部分写成专门的子函数,将自己的程序,重新写了一次。
问题(2):
问题概述:在遇到‘)’后即使后面还有未输出的字符,但我的字符栈就不输出也不输入了,而且我的检查程序还没有报错ERROR
解决过程:我用printf将循环中每个字符栈的字符以及其拥有的字符个数打印出来,进行调试。发现‘)’后字符栈的下一个进栈点错误的出现在-1处,由于我的判断语句只判断了前一个字符的种类是什么以及是不是在0处,没有考虑会出现小于0的情况。所以经过‘)’后就不进入判断语句。就造成了没有报错但输出有错的情况。
解决方法:字符栈本不可能在-1处。我发现在子函数中我已经x-1了,但主函数的循环里我又-1,两次操作重复了,于是出现了负数。所以我删去了循环的-1。
6.测试结果和分析
7. 源代码(完成了去年说的要改进的计划,去年没学栈但老师让我们写四则运算的苦逼场景还历历在目,但在坚持2天后还真写了一个四则运算的程序(虽然他不能计算括号,阶乘,次幂但它可以做到理论上无限的加减乘除,支持小数大数),收获感满满,就写了一个不太成熟的博客并说之后会完善他,今天就完善了。)
8.寄语
这次博客不是老师的任务,倒是给过去的自己一个交代吧。前方道阻且长啊,HURRY up!!