算术表达式求值
数据结构表达式求值实验报告
竭诚为您提供优质文档/双击可除数据结构表达式求值实验报告篇一:数据结构实验二——算术表达式求值实验报告《数据结构与数据库》实验报告实验题目算术表达式求值学院:化学与材料科学学院专业班级:09级材料科学与工程系pb0920603姓学邮名:李维谷号:pb09206285箱:指导教师:贾伯琪实验时间:20XX年10月10日一、需要分析问题描述:表达式计算是实现程序设计语言的基本问题之一,它的实现是栈的应用的一个典型例子。
设计一个程序,演示通过将数学表达式字符串转化为后缀表达式,并通过后缀表达式结合栈的应用实现对算术表达式进行四则混合运算。
问题分析:在计算机中,算术表达式由常量、变量、运算符和括号组成。
由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。
因而在程序设计时,借助栈实现。
设置运算符栈(字符型)和运算数栈(浮点型)辅助分析算符优先关系。
在读入表达式的字符序列的同时完成运算符和运算数的识别处理,然后进行运算数的数值转换在进行四则运算。
在运算之后输出正确运算结果,输入表达式后演示在求值中运算数栈内的栈顶数据变化过程,最后得到运算结果。
算法规定:输入形式:一个(:数据结构表达式求值实验报告)算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。
为使实验更完善,允许操作数为实数,操作符为(、)、.(表示小数点)、+、-、*、/、^(表示乘方),用#表示结束。
输出形式:演示表达式运算的中间结果和整个表达式的最终结果,以浮点型输出。
程序功能:对实数内的加减乘除乘方运算能正确的运算出结果,并能正确对错误输入和无定义的运算报错,能连续测试多组数据。
测试数据:正确输入:12*(3.6/3+4^2-1)#输出结果:194.4无定义运算:12*(3.6/(2^2-4)+1)#输出结果:表达式出错,除数为0,无意义错误输入:12+s#输出结果:eRRoR!二、概要设计拟采用两种类型的展分别对操作数和操作符进行操作。
数据结构算术表达式求值实验
北京理工大学珠海学院《数据结构》课程设计报告题目:____________算术表达式求值_________________所在学院:专业班级:学生姓名:指导教师:2010年 05 月 26 日目录1.前言 (1)2.概要设计 (1)2。
1 数据结构设计 (1)2.2 算法设计 (1)2。
3 ADT描述 (2)2.4 功能模块分析 (2)3.详细设计 (3)3.1 数据存储结构设计 (3)3.2主要算法流程图(或算法伪代码) (3)4.软件测试 (6)5.心得体会 (8)参考文献 (8)附录 (8)1.前言在计算机中,算术表达式由常量、变量、运算符和括号组成。
由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。
因而在程序设计时,借助栈实现。
算法输入:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。
为简化,规定操作数只能为正整数,操作符为+、—*、/,用#表示结束。
算法输出:表达式运算结果.算法要点:设置运算符栈和运算数栈辅助分析算符优先关系。
在读入表达式的字符序列的同时,完成运算符和运算数的识别处理,以及相应运算。
2.概要设计2。
1 数据结构设计任何一个表达式都是由操作符,运算符和界限符组成的.我们分别用顺序栈来寄存表达式的操作数和运算符.栈是限定于紧仅在表尾进行插入或删除操作的线性表。
顺序栈的存储结构是利用一组连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置,base为栈底指针,在顺序栈中,它始终指向栈底,即top=base可作为栈空的标记,每当插入新的栈顶元素时,指针top增1,删除栈顶元素时,指针top减1。
2.2 算法设计为了实现算符优先算法。
可以使用两个工作栈。
一个称为OPTR,用以寄存运算符,另一个称做OPND,用以寄存操作数或运算结果.1。
首先置操作数栈为空栈,表达式起始符”#"为运算符栈的栈底元素;2.依次读入表达式,若是操作符即进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先权后作相应的操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为”#”)。
数据结构-算术表达式求值(含需求分析和源代码)
需求分析(附代码)一、需求分析(1)首先定义两个栈OPTR、OPND,栈OPTR用于存放运算符,栈OPND 用于存放操作数;定义一个一维数组expr【】存放表达式串。
(2)主函数主要包括两部分:(1)判断运算符优先权,返回优先权高的;(2)操作函数。
(3)开始将‘#’入操作符栈,通过一个函数来判别算术运算符的优先级。
且规定‘#’的优先级最低。
在输入表达式的最后输入‘#’,代表表达式输入结束。
在表达式输入过程中,遇操作数则直接入栈。
遇到运算符则与栈顶运算符比较优先级,当前运算符优先级高(前面的运算还不应执行)则当前运算符入栈,扫描下一符号;否则栈顶运算符出栈,两操作数出栈,进行运算,所得结果入数栈,重新比较当前运算符(注意当前运算符未变)与新栈顶运算符。
如此重复直到栈顶运算符与当前符号均为‘#’,运算结束。
(4)最初实现的加、减、乘、除及带小括号的基本运算,但考虑到实用性,后来的设计中有加上了乘方运算。
在乘方运算中借用了C库中自带的乘方函数pow。
二、概要设计1、设定栈的抽象数据类型定义:ADT Stack {数据对象:D={ ai | ai∈ElemSet, i=1,2,...,n,n≥0 }数据关系:R1={ <ai-1, ai >| ai-1, ai∈D, i=2,...,n }约定an端为栈顶,a1端为栈底。
基本操作:InitStack(&S)操作结果:构造一个空栈S。
DestroyStack(&S)初始条件:栈S已存在。
操作结果:栈S被销毁。
StackEmpty(S)初始条件:栈S已存在。
操作结果:若栈S为空栈,则返回TRUE,否则FALE。
StackLength(S)初始条件:栈S已存在。
操作结果:返回S的元素个数,即栈的长度。
GetTop(S, &e)初始条件:栈S已存在且非空。
操作结果:用e返回S的栈顶元素。
ClearStack(&S)初始条件:栈S已存在。
c语言算术表达式求值
c语言算术表达式求值C语言是一种广泛应用的编程语言,其强大的算术表达式求值功能使其在科学计算、数据处理、游戏开发等领域有着重要的应用。
本文将介绍C语言中算术表达式求值的相关知识,包括运算符、运算符优先级、表达式求值的顺序等内容。
我们需要了解C语言中常用的算术运算符。
C语言支持的算术运算符包括加法(+)、减法(-)、乘法(*)、除法(/)和求余(%)等。
这些运算符用于对数值进行基本的加减乘除运算。
在C语言中,运算符的优先级决定了表达式求值的顺序。
常见的运算符优先级从高到低依次为:1. 括号(()):括号中的表达式具有最高的优先级,可以改变默认的运算次序。
2. 一元运算符:包括正号(+)和负号(-),用于表示正负数。
3. 乘法、除法和求余:乘法(*)、除法(/)和求余(%)的优先级相同,从左到右依次计算。
4. 加法和减法:加法(+)和减法(-)的优先级相同,从左到右依次计算。
在使用C语言进行算术表达式求值时,我们需要遵循这些运算符的优先级规则,以保证表达式的正确求值。
如果表达式中包含多个运算符,我们需要根据优先级确定运算的顺序,可以使用括号来改变默认的运算次序。
下面我们将通过几个例子来说明C语言中算术表达式求值的过程。
例1:求解一个简单的算术表达式假设我们需要计算表达式 3 + 4 * 2,根据运算符优先级规则,先计算乘法,再计算加法。
具体的求解过程如下:1. 计算4 * 2,得到8。
2. 计算3 + 8,得到11。
所以,表达式3 + 4 * 2的值为11。
例2:使用括号改变运算次序假设我们需要计算表达式(3 + 4) * 2,根据运算符优先级规则,先计算括号内的加法,再计算乘法。
具体的求解过程如下:1. 计算3 + 4,得到7。
2. 计算7 * 2,得到14。
所以,表达式(3 + 4) * 2的值为14。
通过以上两个例子,我们可以看到,C语言中的算术表达式求值是按照运算符优先级和运算次序进行的,遵循从左到右的计算规则。
数据结构 算术表达式求值
/**************************************************************************** 2、算术表达式求值(必做) (栈)时间:2012年12月[问题描述]一个算术表达式是由操作数( operand)、运算符(operator )和界限符(delimiter)组成的。
假设操作数是正实数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“# ”,如:#(7+15)*(23-28/4)#。
引入表达式起始、结束符是为了方便。
编程利用“算符优先法”求算术表达式的值。
[基本要求](1)从键盘或文件读入一个合法的算术表达式,输出正确的结果。
(2)显示输入序列和栈的变化过程。
(3)考虑算法的健壮性,当表达式错误时,要给出错误原因的提示。
***************************************************************************/ #include <stdio.h>#include <stdlib.h>#include <string.h>#define OVERFLOW 0#define ERROR 0#define OK 1#define STACK_INIT_SIZE 100 //存储空间初始分配量#define STACKINCREMENT 10 //存储空间分配增量#define MAXSIZE 100#define N 100//*********************************************************************** struct expression{double result;char expstr[MAXSIZE];}exp;typedef struct{char *base; //在栈构造之前和销毁之后,base的值为NULLchar *top; //操作符栈栈顶指针int stacksize; //当前已分配的存储空间,以元素为单位}StackOPTR;//操作符栈typedef struct{float *base; //在栈构造之前和销毁之后,base的值为NULLfloat *top; //操作数栈栈顶指针int stacksize; //当前已分配的存储空间,以元素为单位}StackOPND;//操作数栈//************************栈的基本操作************************************************//***初始化***void InitStack(StackOPTR &S)//操作符栈初始化{S.base=(char *)malloc(STACK_INIT_SIZE * sizeof(char));if(!S.base)exit(OVERFLOW);S.top=S.base;S.stacksize=STACK_INIT_SIZE;}void InitStack(StackOPND &S)//操作数栈初始化{S.base=(float *)malloc(STACK_INIT_SIZE * sizeof(float));if(!S.base)exit(OVERFLOW);S.top=S.base;S.stacksize=STACK_INIT_SIZE;}//***GetTop***int GetTop(StackOPTR S,char &e)//若操作符栈不空,则用e返回s的栈顶元素{if(S.top==S.base)return ERROR;e=*(S.top-1);return OK;}int GetTop(StackOPND S,float &e)//若操作数栈不空,则用e返回s的栈顶元素{if(S.top==S.base)return ERROR;e=*(S.top-1);return OK;}//***Push***void Push(StackOPTR &S,char e)//插入元素e为新的操作符栈顶元素{if(S.top-S.base>=S.stacksize){S.base=(char*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(char));if(!S.base)exit(OVERFLOW);S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;}void Push(StackOPND &S,float e)//插入元素e为新的操作数栈顶元素{if(S.top-S.base>=S.stacksize){S.base=(float*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(float));if(!S.base)exit(OVERFLOW);S.top=S.base+S.stacksize;S.stacksize+=STACKINCREMENT;}*S.top++=e;}//***Pop***int Pop(StackOPTR &S,char &e)//若操作符栈不空,删除s的栈顶元素,用e返回其值{if(S.top==S.base)return ERROR;e=*--S.top;return OK;}int Pop(StackOPND &S,float &e)//若操作数栈不空,删除s的栈顶元素,用e返回其值{if(S.top==S.base)return ERROR;e=*--S.top;return OK;}#define OPSIZE 7//运算符个数char OP[OPSIZE]={'+','-','*','/','(',')','#'};//运算符集合// 表3.1 算符间的优先关系char Prior[7][7] ={'>','>','<','<','<','>','>','>','>','<','<','<','>','>','>','>','>','>','<','>','>','>','>','>','>','<','>','>','<','<','<','<','<','=',' ','>','>','>','>',' ','>','>','<','<','<','<','<',' ','='};//***int In(char c,char *OP)//OP是运算符集合,检验是否为运算符{bool check=false;for(int i=0;i<OPSIZE;i++){if(c==OP[i])check=true;}return check;}//***float Operate(float a,char theta,float b)//进行二元运算aeb {switch(theta){case'+':return a+b;break;case'-':return a-b;break;case'*':return a*b;break;case'/':if(b==0){printf("不得出现0作为除数!\n");return 0;}elsereturn a/b;break;default:return 0;}}//***int Xu_Op(char theta,char *OP)//返回运算符c在OP中的序号{int i;for(i=0;i<OPSIZE;i++){if(theta==OP[i])return i;}return 0;}char Precede(char theta1,char theta2)//判断运算符栈的栈顶运算符theta1和读入的运算符theta2优先关系{return Prior[Xu_Op(theta1,OP)][Xu_Op(theta2,OP)];}//****算法健壮性的检查*******int change(char c)//字符都改成编号{switch(c){case'(': return 0;break;case'#': return 1;break;case')': return 2;break;case'+': return 3;break;case'-': return 3;break;case'*': return 4;break;case'/': return 4;break;case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9': return -1;break;default: return -2;}}int Wrong(char *exp)//检查算法的健壮性{char *p,*q;int i=0;//记录括号,i=0,合法。
c语言算术表达式求值
c语言算术表达式求值【实用版】目录1.引言2.C 语言算术表达式的基本概念3.C 语言算术表达式的求值方法4.实际应用示例5.总结正文【引言】在 C 语言编程中,算术表达式是用来进行数值计算的重要工具。
本篇文章将为大家介绍 C 语言算术表达式的求值方法。
【C 语言算术表达式的基本概念】C 语言中的算术表达式主要包括以下几种:1.一元运算符:例如+、-、*、/等,用于对一个数值进行操作。
2.二元运算符:例如+、-、*、/等,用于对两个数值进行操作。
3.关系运算符:例如<、>、<=、>=、==、!=等,用于比较两个数值的大小或相等性。
4.逻辑运算符:例如&&、||、! 等,用于进行逻辑判断。
【C 语言算术表达式的求值方法】C 语言中,算术表达式的求值主要遵循以下规则:1.先进行括号内的运算,再进行括号外的运算。
2.先进行乘除法运算,再进行加减法运算。
3.关系运算符和逻辑运算符的优先级较低,从左到右依次进行运算。
【实际应用示例】下面我们通过一个实际的 C 语言程序,来演示算术表达式的求值过程。
```c#include <stdio.h>int main() {int a = 10, b = 5;int result;result = a + b * (a - b) / (a * b);printf("The result is: %d", result);return 0;}```在这个程序中,我们定义了两个整数变量 a 和 b,并通过算术表达式计算 result 的值。
根据我们之前提到的算术表达式求值规则,我们可以将这个表达式分解为以下几个步骤:1.计算括号内的值:a - b = 10 - 5 = 52.计算乘法运算:b * (a - b) = 5 * 5 = 253.计算除法运算:(a * b) / (a * b) = 14.计算加法运算:a + 25 = 10 + 25 = 355.输出结果:printf("The result is: %d", result); 输出 35【总结】通过本篇文章的介绍,相信大家已经对 C 语言算术表达式的求值方法有了更加深入的了解。
C#算术表达式求值(后缀法),看这一篇就够了
C#算术表达式求值(后缀法),看这⼀篇就够了⼀、种类介绍算术表达式有三种:前缀表达式、中缀表达式和后缀表达式。
⼀般⽤的是中缀,⽐如1+1,前后缀就是把操作符移到前⾯和后⾯,下⾯简单介绍⼀下这三种表达式。
1、前缀表⽰法前缀表⽰法⼜叫波兰表⽰法,他的操作符置于操作数的前⾯(例:+ 1 2),是波兰数学家扬·武卡谢维奇1920年代引⼊的,⽤于简化命题逻辑。
因为我们⼀般认为操作符是在操作数中间的,所以在⽇常⽣活中⽤的不多,但在计算机科学领域占有⼀席之地。
⼀般的表⽰法对计算机来说处理很⿇烦,每个符号都要考虑优先级,还有括号这种会打乱优先级的存在,将使计算机花费⼤量的资源进⾏解析。
⽽前缀表⽰法没有优先级的概念,他是按顺序处理的。
举个例⼦:9-2*3这个式⼦,计算机需要先分析优先级,先乘后减,找到2*3,再进⾏减操作;化成前缀表⽰法就是:- 9 * 2 3,计算机可以依次读取,操作符作⽤于后⼀个操作数,遇到减就是让9减去后⾯的数,⽽跟着9的是乘,也就是说让9减去乘的结果,这对计算机来说很简单,按顺序来就⾏了。
2、中缀表⽰法这也就是我们⼀般的表⽰法,他的操作符置于操作数的中间(例:1 + 2),前⾯也说过这种⽅法不容易被计算机解析,但他符合⼈们的普遍⽤法,许多编程语⾔也就⽤这种⽅法了。
在中缀表⽰法中括号是必须有的,要不然运算顺序会乱掉。
3、后缀表⽰法后缀表⽰法⼜叫逆波兰表⽰法,他的操作符置于操作数的后⾯(例:1 2 +),他和前缀表⽰法都对计算机⽐较友好,但他很容易⽤堆栈解析,所以在计算机中⽤的很多。
他的解释过程⼀般是:操作数⼊栈;遇到操作符时,操作数出栈,求值,将结果⼊栈;当⼀遍后,栈顶就是表达式的值。
因此逆波兰表达式的求值使⽤堆栈结构很容易实现,且能很快求值。
注意:逆波兰记法并不是简单的波兰表达式的反转。
因为对于不满⾜交换律的操作符,它的操作数写法仍然是常规顺序,如,波兰记法/ 6 3的逆波兰记法是6 3 /⽽不是3 6 /;数字的数位写法也是常规顺序。
利用栈来实现算术表达式求值的算法
利用栈来实现算术表达式求值的算法利用栈来实现算术表达式求值的算法算术表达式是指按照一定规则组成的运算式,包含数字、运算符和括号。
在计算机中,求解算术表达式是一项基本的数学运算任务。
根据算术表达式的性质,我们可以考虑利用栈这一数据结构来实现求值算法。
一、算法思路首先,我们需要明确一个重要概念——逆波兰表达式(ReversePolish notation)。
逆波兰表达式是一种没有括号的算术表达式,其运算规则是先计算后面的数字和运算符,再计算前面的数字和运算符。
例如,对于算术表达式“3+4*5-6”,其对应的逆波兰表达式为“3 45 * +6 -”。
那么,我们可以利用栈来实现将中缀表达式转化为逆波兰表达式的过程,具体步骤如下:1. 创建两个栈——操作数栈和操作符栈。
2. 从左到右扫描中缀表达式的每一个数字和运算符,遇到数字则压入操作数栈中,遇到运算符则进行如下操作:(1)如果操作符栈为空或当前运算符的优先级大于栈顶运算符的优先级,则将当前运算符压入操作符栈中。
(2)如果当前运算符的优先级小于或等于栈顶运算符的优先级,则将栈顶运算符弹出并加入操作数栈中,重复此过程直到遇到优先级较低的运算符或操作符栈为空为止,然后将当前运算符压入操作符栈中。
3. 扫描完中缀表达式后,若操作符栈不为空,则将其中所有运算符弹出并加入操作数栈中。
4. 最终,操作数栈中存放的就是逆波兰表达式,我们可以按照逆波兰表达式的计算规则来计算其结果。
二、算法优点利用栈来实现算术表达式求值的算法具有以下优点:1. 代码简洁易懂,易于实现和维护。
2. 由于将中缀表达式转化为逆波兰表达式后,可以减少运算符的优先级关系而消除括号,从而减少求值的复杂度,提高程序的执行效率。
三、代码实现下面是利用栈来实现算术表达式求值的算法的Python代码实现:```pythonclass Stack:def __init__(self):self.items = []def push(self, item):self.items.append(item)def pop(self):return self.items.pop()def peek(self):return self.items[-1]def is_empty(self):return len(self.items) == 0def size(self):return len(self.items)def calculate(op_num1, op_num2, operator):if operator == "+":return op_num1 + op_num2elif operator == "-":return op_num1 - op_num2elif operator == "*":return op_num1 * op_num2elif operator == "/":return op_num1 / op_num2def infix_to_postfix(infix_expr):opstack = Stack()postfix_expr = []prec = {"+": 1, "-": 1, "*": 2, "/": 2, "(": 0} token_list = infix_expr.split()for token in token_list:if token.isdigit():postfix_expr.append(token)elif token == '(':opstack.push(token)elif token == ')':top_token = opstack.pop()while top_token != '(':postfix_expr.append(top_token)top_token = opstack.pop()else:while (not opstack.is_empty()) and(prec[opstack.peek()] >= prec[token]):postfix_expr.append(opstack.pop())opstack.push(token)while not opstack.is_empty():postfix_expr.append(opstack.pop())return " ".join(postfix_expr)def postfix_eval(postfix_expr):opstack = Stack()token_list = postfix_expr.split()for token in token_list:if token.isdigit():opstack.push(int(token))else:op_num2 = opstack.pop()op_num1 = opstack.pop()result = calculate(op_num1, op_num2, token) opstack.push(result)return opstack.pop()infix_expr = "3 + 4 * 5 - 6"postfix_expr = infix_to_postfix(infix_expr)print(postfix_expr)print(postfix_eval(postfix_expr))```四、总结算术表达式求值是一项常见的数学运算任务,利用栈这一数据结构来实现求值算法是一种简单有效的方法,它将中缀表达式转化为逆波兰表达式后,可以消除括号并减少运算符的优先级关系,从而提高程序的执行效率。
表达式求值(数据结构)
结束算法,此时在OPND栈的栈顶得到 运算结果。
① 若ch是操作数,进OPND栈,从中缀表达式 取下一字符送入ch; ② 若ch是操作符,比较栈外icp(ch)的优先级和 栈内isp(OPTR)的优先级: 若icp(ch) > isp(OPTR),则ch进OPTR栈, 从中缀表达式取下一字符送入ch; 若icp(ch) < isp(OPTR),则从OPND栈退出 a2 和 a1 , 从 OPTR 栈 退 出 θ, 形 成 运 算 指 令 (a1)θ(a2),结果进OPND栈; 若icp(ch) == isp(OPTR) 且ch == “)”,则从 OPTR栈退出栈顶的“(”,对消括号,然后从 中缀表达式取下一字符送入ch;
优先级 操作符
1
单目-、!
2
*、/、%
3
+、-
4 <、<=、>、>=
5
==、!=
6
&&
7
||
一般表达式的操作符有4种类型:
1 算术操作符 如双目操作符(+、-、 *、/ 和%)以及单目操作符(-);
2 关系操作符 包括<、<=、==、!=、 >=、>。这些操作符主要用于比较;
3 逻辑操作符 如与(&&)、或(||)、非 (!);
38
icp (栈外) 0 8 6 4
21
isp叫做栈内(in stack priority)优先数。
icp叫做栈外(in coming priority)优先数。
操作符优先数相等的情况只出现在括号 配对或栈底的“;”号与输入流最后的“;” 号配对时。
表达式求值算法
表达式求值算法表达式求值算法是计算机科学中的重要概念之一,用于计算数学表达式的结果。
在编程语言中,表达式求值是一项基本的操作,并且经常在计算过程中需要用到。
本文将介绍一些常见的表达式求值算法及其实现。
1. 逆波兰表达式法逆波兰表达式法是一种用于计算数学表达式的算法,它使用后缀表达式(也称为逆波兰表达式)来表示表达式。
逆波兰表达式是将操作符放在操作数之后的一种表示方法。
对于任意一个数学表达式,都可以通过将中缀表达式转换为后缀表达式,然后使用栈结构计算得到结果。
逆波兰表达式法的优点是计算顺序明确,不需要考虑运算符的优先级和括号的处理。
2. 中缀表达式转后缀表达式法中缀表达式是我们常见的数学表达式,如 3 + 4 * 5。
在中缀表达式中,操作符的优先级和括号起着很大的作用。
为了将中缀表达式转换为后缀表达式,我们需要使用到栈结构。
具体的算法如下:- 遍历中缀表达式的每个元素。
- 如果是操作数,则直接输出。
- 如果是操作符,则判断其与栈顶操作符的优先级,决定是否将其压入栈。
- 如果是左括号,则直接压入栈。
- 如果是右括号,则依次弹出栈顶操作符,并输出,直到遇到左括号为止。
- 遍历完表达式后,如果栈不为空,则依次弹出栈顶操作符,并输出。
3. 后缀表达式求值法后缀表达式(逆波兰表达式)的求值方法相对简单。
我们可以使用栈结构来计算后缀表达式的结果。
具体的算法如下:- 遍历后缀表达式的每个元素。
- 如果是操作数,则将其压入栈。
- 如果是操作符,则弹出栈顶的两个操作数,执行相应的计算,并将结果压入栈。
- 遍历完后缀表达式后,栈中最后剩下的元素即为计算结果。
4. 二叉树表示法除了逆波兰表达式法和中缀表达式法,我们还可以使用二叉树来表示表达式,并通过遍历二叉树来计算表达式的结果。
具体的算法如下:- 构建二叉树,将表达式的操作符作为根节点,将操作数作为叶节点。
- 通过后序遍历二叉树,计算出每个子树的值,并将结果返回给其父节点。
简单算术表达式的二叉树的构建和求值
一、概述二、算术表达式的二叉树表示1. 什么是二叉树2. 算术表达式的二叉树表示方法三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式2. 后缀表达式构建二叉树四、算术表达式二叉树的求值五、应用举例六、总结一、概述在数学和计算机科学中,处理算术表达式是一个常见的问题。
在计算机中,算术表达式通常以中缀、前缀或后缀的形式出现,其中中缀表达式最为常见。
而采用二叉树来表示和求解算术表达式,是一种常见且高效的方法。
二、算术表达式的二叉树表示1. 什么是二叉树二叉树是一种树形数据结构,它的每个节点最多只能有两个子节点,分别是左子节点和右子节点。
二叉树可以为空,也可以是非空的。
2. 算术表达式的二叉树表示方法在二叉树中,每个节点要么是操作符,要么是操作数。
操作符节点的左子节点和右子节点分别表示运算符的两个操作数,而操作数节点则不包含任何子节点。
通过这种方式,可以将算术表达式表示为一个二叉树结构。
三、算术表达式二叉树的构建1. 中缀表达式转换为后缀表达式为了构建算术表达式的二叉树,首先需要将中缀表达式转换为后缀表达式。
中缀表达式是人们常见的形式,例如"2 + 3 * 5",而后缀表达式则更适合计算机处理,例如"2 3 5 * +"。
将中缀转后缀的算法即为中缀表达式的后缀转换法则。
2. 后缀表达式构建二叉树构建二叉树的过程通常采用栈来辅助完成。
从左到右扫描后缀表达式,对于每个元素,如果是操作数,则入栈;如果是操作符,则弹出栈顶两个元素作为其左右子节点,然后将操作符节点入栈。
最终栈中只剩一个节点,即为构建的二叉树的根节点。
四、算术表达式二叉树的求值算术表达式二叉树的求值是递归进行的。
对于二叉树的每个节点,如果是操作符节点,则递归求解其左右子节点的值,并进行相应的操作;如果是操作数节点,则直接返回其值。
最终得到根节点的值,即为整个算术表达式的值。
五、应用举例以中缀表达式"2 + 3 * 5"为例,首先将其转换为后缀表达式"2 3 5 * +",然后根据后缀表达式构建二叉树,最终求得二叉树的根节点即为算术表达式的值。
C语言表达式求值
C语言表达式求值
c语言有丰富的表达式,这是它的特点之一,表达式主要有4类,算术表达式,赋值表达式,逗号表达式,关系表达式1.算术表达式就是包含算术运算符(如+-/*%等)的表达式(不是语句,后面没有分号),如:a+b,a%b,a+b-c*d,3+5等,算术表达式的值就是最后算出的结果,如3+5这个表达式的值就是82.赋值表达式,就是含有赋值运算符=的表达式,如a=5,b=3,c='A'等,=左边的a,b,c称为左值,必须为变量,=右边的5,3,'A'称为右值,必须为常量,赋值表达式的值为右值,如a=3的值为3,c='A'的值为字母A的ascii码65(当然也可以认为它的值就是字母A)3.逗号表达式就是含有逗号的表达式,形式:表达式1,表达式2,表达式3.......如a,b,c3,5,7a=3,b=4,c=63,a=5,b=6等逗号表达式的值为,最右边的表达式的值,如3,4,5的值就是5,表达式
a=3,b=4,c=6的值就是表达式b=6的值,
由上述分析知,表达式b=6的值就是6,所以表达式
a=3,b=4,c=6的值就是64.关系表达式,指含有关系运算符
(如><>====<等)的表达式(其实也是算术表达式的一种)如
a>b,a>6,6>5,3<2,4==6等,如果表达式的关系是正确的,那么表达式的值为1,否则为0如6>5正确,表达式的值为1,3<2,和4==6错误,表达式的值为0当然可以细分为很多种表达式,不过主要也就是这几种的变型。
算术表达式求值演示-课程设计报告
算术表达式求值演示目录第一章概述 (1)第二章系统分析 (1)第三章概要设计 (2)第四章详细设计 (5)第五章运行与测试 (13)第六章总结与心得 (16)参考文献 (16)第一章概述课程设计是实践性教学中的一个重要环节,它以某一课程为基础,可以涉及和课程相关的各个方面,是一门独立于课程之外的特殊课程。
课程设计是让同学们对所学的课程更全面的学习和应用,理解和掌握课程的相关知识。
《数据结构》是一门重要的专业基础课,是计算机理论和应用的核心基础课程。
数据结构课程设计,要求学生在数据结构的逻辑特性和物理表示、数据结构的选择和应用、算法的设计及其实现等方面,加深对课程基本内容的理解。
同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
在这次的课程设计中我选择的题目是算术表达式求值演示。
表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。
设计一个程序,演示用算符优先法对算术表达式求值的过程。
深入了解栈和队列的特性,以便在解决实际问题中灵活运用它们,同时加深对这种结构的理解和认识。
第二章系统分析1.以字符列的形式从终端输入语法正确的、不含变量的整数表达式。
利用已知的算符优先关系,实现对算术四则混合运算表达式的求值,并仿照教科书的例子在求值中运算符栈、运算数栈、输入字符和主要操作的变化过程。
2.一般来说,计算机解决一个具体问题时,需要经过几个步骤:首先要从具体问题抽象出一个适当的数学模型,然后设计一个解决此数学模型的算法,最后编出程序,进行测试,调试直至得到想要的答案。
对于算术表达式这个程序,主要利用栈,把运算的先后步骤进行分析并实现简单的运算!为实现算符优先算法,可以使用两个栈,一个用以寄存运算符,另一个用以寄存操作数和运算结果。
3.演示程序是以用户于计算机的对话方式执行,这需要一个模块来完成使用者与计算机语言的转化。
4.程序执行时的命令:本程序为了使用具体,采用菜单式的方式来完成程序的演示,几乎不用输入什么特殊的命令,只需按提示输入表达式即可。
数据结构实验二——算术表达式求值实验报告
数据结构实验二——算术表达式求值实验报告算术表达式求值实验报告一、引言算术表达式求值是计算机科学中一个重要的基础问题,它涉及到了数据结构和算法的应用。
本实验旨在通过实现一个算术表达式求值的程序,加深对数据结构中栈的理解和应用,并掌握算术表达式的求值过程。
二、实验目的1. 理解算术表达式的基本概念和求值过程;2. 掌握栈的基本操作和应用;3. 实现一个能够正确求解算术表达式的程序;4. 进一步熟悉编程语言的使用。
三、实验内容1. 设计并实现一个栈的数据结构;2. 实现算术表达式求值的算法;3. 编写测试用例,验证程序的正确性;4. 进行性能测试,分析算法的时间复杂度。
四、实验方法与步骤1. 设计栈的数据结构在本实验中,我们选择使用数组来实现栈的数据结构。
栈的基本操作包括入栈(push)、出栈(pop)、判断栈空(isEmpty)和获取栈顶元素(top)等。
2. 算术表达式求值算法算术表达式求值的一种常用算法是通过后缀表达式进行求值。
具体步骤如下: - 将中缀表达式转换为后缀表达式;- 通过栈来求解后缀表达式;- 返回最终的计算结果。
3. 编写测试用例编写一系列测试用例,包括不同类型的算术表达式,以验证程序的正确性。
例如:- 简单的四则运算表达式:2 + 3 * 4 - 5;- 包含括号的表达式:(2 + 3) * (4 - 5);- 包含多位数的表达式:12 + 34 * 56;- 包含浮点数的表达式:3.14 + 2.71828。
4. 性能测试和时间复杂度分析针对不同规模的输入数据,进行性能测试,记录程序的运行时间。
同时,分析算法的时间复杂度,验证算法的效率。
五、实验结果与分析我们设计并实现了一个栈的数据结构,并成功地完成了算术表达式求值的程序。
通过对一系列测试用例的验证,我们发现程序能够正确地求解各种类型的算术表达式,并返回正确的计算结果。
在性能测试中,我们对不同规模的输入数据进行了测试,并记录了程序的运行时间。
算术表达式求值实验报告
算术表达式求值实验报告1. 背景算术表达式求值是计算机科学中的基本问题之一,涉及到对数学表达式的解析和计算。
在计算机编程中,经常需要对用户输入的数学表达式进行求值,以得到正确的计算结果。
因此,研究如何高效地求解算术表达式是非常重要的。
在本次实验中,我们将探索不同方法来求解算术表达式,并比较它们的性能和准确性。
我们将使用Python语言作为实现工具,并通过编写代码来实现不同方法。
2. 分析2.1 表达式解析在进行表达式求值之前,我们首先需要对输入的数学表达式进行解析。
解析过程主要包括以下几个步骤:1.去除空格:将输入的字符串中的空格字符去除。
2.分词:将字符串按照运算符和操作数进行分割,得到一个由标记组成的列表。
3.构建语法树:根据分词结果构建一个语法树,用于表示数学表达式的结构。
4.求值:通过遍历语法树并执行相应操作,最终得到表达式的值。
2.2 求值方法在本次实验中,我们将尝试以下两种不同的求值方法:1.递归求值:通过递归地遍历语法树来求解表达式。
递归求值的优点是简单易懂,但可能存在性能问题。
2.栈求值:使用栈数据结构来辅助求解表达式。
栈可以有效地处理运算符的优先级和括号的匹配问题。
2.3 性能评估为了评估不同方法的性能,我们将使用一组测试用例来对其进行比较。
测试用例包括不同长度和复杂度的数学表达式,以及各种运算符和括号的组合。
我们将使用Python内置的time模块来测量每种方法的执行时间,并比较它们之间的差异。
此外,我们还将检查每种方法是否能正确地计算出表达式的结果。
3. 实验结果3.1 表达式解析在实现表达式解析过程时,我们首先去除输入字符串中的空格,并将其转换为一个字符列表。
然后,我们使用递归下降法来构建语法树。
具体而言,我们定义了以下几个函数:1.parse_expression(tokens):该函数接受一个标记列表作为参数,并返回一个表示整个表达式的语法树。
2.parse_term(tokens):该函数接受一个标记列表作为参数,并返回一个表示项的语法树。
算术表达式求值数据结构实验报告
算法的正确性和效率分析
正确性
所有实现的数据结构都正确地实现了算术表达式求值的功能,没有出现计算错 误的情况。
效率
在处理大量数据时,使用堆栈(Stack)和队列(Queue)的数据结构表现最 佳。堆栈在处理后缀表达式时效率最高,而队列在处理中缀表达式时效率最高 。
数据结构优化的效果评估
使用哈希表(Hash Table)
展望未来,希望能够进一步研究算术 表达式求值算法的优化和改进,提高 计算效率和精度。
THANKS
感谢观看
05
列表(List)
数组(Array) 元组(Tuple) 集合(Set)
字典( Dictiona…
由于列表在Python中是动 态数组,其性能在处理大 量数据时相对较差。在算 术表达式求值中,列表的 平均执行时间最长。
使用NumPy库的数组结构 ,其性能在处理大量数据 时优于列表。但在算术表 达式求值中,其性能仍然 不如其他数据结构。
03
了解如何使用栈数据结构实现括号匹配和回退机制 。
掌握数据结构在算术表达式求值中的应用
01 熟悉使用数组、链表等基本数据结构存储和操作 算术表达式。
02 掌握如何使用树形数据结构表示算术表达式,如 二叉树或表达式树。
03 了解动态规划在优化算术表达式求值中的运用。
提高编程能力和解决问题的能力
01
在处理重复元素时,使用哈希表可以显著提高数据结构的效率。在算术表达式求值中,哈希表的使用可以减少重 复计算和查找的时间。
预处理输入数据
对输入的算术表达式进行预处理,如括号消除、指数化等,也可以提高数据结构的效率。预处理可以减少运算的 复杂度和时间。
05
实验总结
本次实验的收获和体会
编程中表达式的求值规则与示例
编程中表达式的求值规则与示例在计算机编程中,表达式是由操作数和操作符组成的数学或逻辑式子,用于执行各种计算和操作。
表达式的求值是指根据特定的规则和优先级计算表达式的结果。
本文将介绍一些常见的表达式求值规则,并提供一些示例来帮助读者更好地理解这些概念。
1. 算术表达式的求值规则算术表达式是最常见的表达式类型之一,用于执行数学运算。
在算术表达式中,我们通常使用加法、减法、乘法和除法等基本算术运算符。
求值规则:- 先计算括号内的表达式。
- 乘法和除法的优先级高于加法和减法。
按照从左到右的顺序计算乘法和除法。
- 加法和减法的优先级相同,按照从左到右的顺序计算。
示例:1. 2 + 3 * 4 - 1首先计算乘法:3 * 4 = 12然后计算加法和减法:2 + 12 - 1 = 132. (2 + 3) * 4 / 2首先计算括号内的表达式:2 + 3 = 5然后计算乘法和除法:5 * 4 / 2 = 102. 逻辑表达式的求值规则逻辑表达式用于执行逻辑运算,例如判断条件是否为真或假。
在逻辑表达式中,我们通常使用与、或和非等逻辑运算符。
求值规则:- 先计算括号内的表达式。
- 非运算符的优先级最高,其次是与运算符,最后是或运算符。
- 与运算符在计算时,只有当两个操作数都为真时,结果才为真。
- 或运算符在计算时,只有当两个操作数都为假时,结果才为假。
示例:1. (2 > 1) && (3 < 5)首先计算括号内的表达式:2 > 1 和 3 < 5 都为真然后计算与运算符:真 && 真 = 真2. (2 > 1) || (3 > 5)首先计算括号内的表达式:2 > 1 为真,但 3 > 5 为假然后计算或运算符:真 || 假 = 真3. 字符串连接表达式的求值规则字符串连接表达式用于将多个字符串拼接在一起。
在字符串连接表达式中,我们使用加号 (+) 运算符来实现字符串的连接。
算术表达式求值算法解析
迭代算法在处理复杂表达式时效率较高,因为避免了重复计算,但在处理简单表达式时,由于需要遍历整个表达 式,效率较低。
算法适用范围比较
递归算法
递归算法适用于处理简单的算术表达式 ,如加减乘除等。
VS
迭代算法
迭代算法适用于处理复杂的算术表达式, 如包含括号、指数、对数等运算的表达式 。
算法优缺点比较
预测分析法的优点是处理效率较高,适用于大规模的算术 表达式处理,但缺点是需要使用大量的栈空间,且对于复 杂的算术表达式处理能力有限。
逆波兰表示法
逆波兰表示法是一种不需要括号来表示运算符优先级的方法,通 过将操作数放在前面,运算符放在后面来表示算术表达式。
逆波兰表示法将算术表达式转换为逆波兰表示形式后,可以直接 从左到右依次读取并计算表达式的值。
高程序的执行效率。例如,通过消除冗余计算、简化表达式等手段来优
化代码。
在数学计算器中的应用
表达式求值
数学计算器需要能够对用户输入的算术表达式进行求值,以便得到计算结果。算术表达式求值算法可以用于实现这一 功能,快速准确地计算表达式的值。
符号计算
数学计算器可能需要支持符号计算,即对包含未知数的算术表达式进行求解。算术表达式求值算法可以用于实现符号 计算,通过迭代和近似方法求解表达式的根或极值等。
多精度计算
在一些情况下,数学计算器需要支持多精度计算,以避免浮点数精度问题。算术表达式求值算法可以用 于实现多精度计算,提供更高的计算精度和可靠性。
在人工智能领域的应用
机器学习
数据推理
在机器学习领域,算术表达式求值算 法可以用于实现特征工程和模型训练 过程中的数值计算。例如,在神经网 络训练中,需要对权重、偏差等参数 进行迭代更新,算术表达式求值算法 可以高效地完成这些计算任务。
C语言_算术表达式求值_代码
C语言_算术表达式求值_代码源代码://用来存储字符的结点类型typedef struct CharNode{char c;struct CharNode *next;}CharNode;//用来存储数的结点类型typedef struct IntNode{long double i;struct IntNode *next;}IntNode;//用来存储数的结点类型typedef struct Node{long double n;struct Node_ys_char *next;}Node;//用来存储运算符的结点类型typedef struct Node_ys_char{char c;struct Node_ys_char *next_c;struct Node *next;}Node_ys_char;char Precede(char x,char y)//运算符优先级判断{ int i,j;int from[5][5]={{0,0,-1,-1,0},{0,0,-1,-1,0},{1,1,0,0,1},{1,1,0,0,1},{0,0,-1,-1,0}};//定义一个二维数组存放算术符号的优先级switch(x){case '+':i=0;break;case '-':i=1;break;case '*':i=2;break;case '/':i=3;break;case '#':i=4;break;}switch(y){case '+':j=0;break;case '-':j=1;break;case '*':j=2;break;case '/':j=3;break;case '#':j=4;break;}if(from[i][j]==1)//说明运算符i的优先级比j的优先级高return '>';if(from[i][j]==-1)return '<';elsereturn '=';}//输入表达式,并对特殊情况做处理CharNode *CreatRegister(){CharNode *top,*p,*q,*e;top=(CharNode *)malloc(sizeof(CharNode)); p=q=top;scanf("%c",&p->c);scanf("%c",&p->c);if(q->c=='-'){p=(CharNode *)malloc(sizeof(CharNode)); p->c='0';p->next=q;top=p;p=q;}if(q->c=='('){e=(CharNode *)malloc(sizeof(CharNode)); e->c='0';p=(CharNode *)malloc(sizeof(CharNode)); p->c='+';e->next=p;p->next=q;p=q;top=e;}while(p->c!='#'){q=(CharNode *)malloc(sizeof(CharNode)); scanf("%c",&q->c);if((p->c=='(')&&(q->c=='-')){e=(CharNode *)malloc(sizeof(CharNode));e->c='0';e->next=q;p->next=e;p=q;}else{p->next=q;p=q;}}p->c='+';p->next=(CharNode *)malloc(sizeof(CharNode)); p->next->c='0';p=p->next;p->next=(CharNode *)malloc(sizeof(CharNode)); p->next->c='#';return top;}//将数与运算符分开,并将其他进制转化为10进制Node *StackChange(CharNode *top,int m){CharNode *p,*q;long double x=0,y=0;char a[10],b[10];int n=0,i=0,JiWei,max,min=47,mark_1=0,mark_2=0,h,k=0; Node *node,*head;Node_ys_char *node_char;switch(m){case 2:JiWei=2;max=50;break;case 8:JiWei=8;max=56;break;case 10:JiWei=10;max=97;break;case 16:JiWei=16;max=103;break;}p=q=top;while(p->c !='#'){while((q->c>min)&&(q->cc==46)) {if(q->c==46){mark_1=1;q=q->next;}if(mark_1==0){a[n]=q->c;q=q->next;n++;}if(mark_1==1){b[i]=q->c;q=q->next;i++;}}for(h=n-1;h>=0;h--){x=(a[n-h-1]-48)*pow(JiWei,h)+x;// }for(h=0;h<i;h++)< p="">{y=y+(b[h]-48)*pow(JiWei,(-(h+1)));//}node=(Node *)malloc(sizeof(Node));//node->n=x+y;mark_1=0;n=0;i=0;if(mark_2==1)node_char->next=node;node_char=(Node_ys_char *)malloc(sizeof(Node_ys_char)); node_char->c=q->c;node->next=node_char;node_char->next_c=NULL;node_char->next=NULL;if(q->c=='#'){node->next=(Node_ys_char *)malloc(sizeof(Node_ys_char));node->next->c='#';return head;}q=q->next;if(q->c<=min)while(q->c<=min){node_char->next_c=(Node_ys_char*)malloc(sizeof(Node_ys_char));node_char->next_c->c=q->c;q=q->next ;//node->next=node_char;node_char=node_char->next_c;node_char->next_c=NULL;node_char->next=NULL;}else{node->next=node_char;node_char->next_c=NULL;node_char->next=NULL;}p=q;n=0;x=0;y=0;if(mark_2==0){head=node;mark_2=1;}}return head;}//作只有加减乘除运算的表达式求值Node *Compute(Node *p){int mark=0;Node *m,*n;char max_char,min_char;m=n=p;while(p->next->c!='#'){max_char=n->next->c;n=n->next->next;min_char=n->next->c;if((Precede(max_char,min_char)=='<'||Precede(max_char,min _char)=='=')&&mark!=1) {m=n;}if(Precede(max_char,min_char)=='>'||mark==1){switch(m->next->c){case '+':m->n =m->n + n->n ;break;case '-':m->n =m->n - n->n ;break;case '*':m->n =m->n * n->n ;break;case '/':m->n =m->n / n->n ;break;}m->next=n->next;n=m;}if(m->next->c=='#'){m=n=p;mark=1;}}return m;}//求用户输入表达式的值Node *GetOutcome(Node *head){Node *p,*q,*R;Node_ys_char *m,*n,*t,*k;n=(Node_ys_char *)malloc(sizeof(Node_ys_char)); n->c='(';p=q=head;while((n->c!=')')&&(q->next->c!='#')){if(q->next->c=='('){m=q->next;k=m;}else if(q->next->next_c==NULL) q=q->next->next;else{m=q->next->next_c;k=q->next;// t=q->next;if(m->c=='('){t=k;k=m;}while(m->next_c!=NULL){m=m->next_c;if(m->c=='('){t=k;k=m;}}q=m->next ;}if(q->next->c==')'){n=q->next;}}if(n->c==')'){p=k->next;q->next->c='#';R=Compute(p);t->next =R;t->next_c=NULL;R->next=n->next_c;GetOutcome(head);}else{R=Compute(head);return R;}}main(){int m;//进制char a;CharNode *top_1;Node *top_2,*R;printf("\n\n");printf("███████████████████████████████████████\n");printf("████\n");printf("██表达式求值系统██\n");printf("████\n");printf("███████████████████████████████████████\n");printf("本程序可分别进行2进制,8进制,10进制,16进制的加减乘除运算:\n");loop:printf("...............请输入进制..............\n");printf("你选的进制为:");scanf("%d",&m);printf("请输入表达式,表达式请以#结尾:\n");top_1=CreatRegister();//录入表达式,并对特殊情况作处理,将头指针带回;top_2=StackChange(top_1,m);//进制转换,将数与运算符分开,将头指针带回;R=GetOutcome(top_2);得出结果printf("运算结果的十进制形式为:\n");printf("%lf",R->n);printf("\n继续进行运算请输入y否则退出:\n");scanf("%c",&a);scanf("%c",&a);if(a=='y'||a=='Y')goto loop;}</i;h++)<>。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
题目:算术表达式求值问题内容:一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。
假设操作数是正整数,运算符只含加减乘除等四种运算符,界限符有左右括号和表达式起始、结束符“#”,如:#(7+15)*(23-28/4)#。
引入表达式起始、结束符是为了方便。
编程利用“算符优先法”求算术表达式的值。
要求:(1)从键盘读入一个合法的算术表达式,输出正确的结果。
(2)显示输入序列和栈的变化过程。
选作内容:操作数类型扩充到实数。
一:问题分析和任务定义1.问题分析:分析题目并参考书目可以基本了解完成一个算术表达式所存在的问题。
对一个表达式来说,由于各种运算符和界限符的运用,运算符和界限符的优先级决定了算术表达式不是简单的从左往右的运算。
因此设计算法完成算术表达式时就要考虑各运算符和界限符的优先级,同时还要注意操作数与算符的判断。
在算法中要求完成操作数、运算符和界限符的出入栈,运算符和界限符的优先级比较和操作数之间的运算。
最后完成的算法要求输入一个算术表达式,能够正确的计算出来它的最后结果并输出。
为了不用考虑算符优先级,将输入的中缀表达式转换成后缀表达式。
这样就可以知道实现本程序需要进行的操作:1)建立空栈,存储信息;2)运用函数实现出入栈和取栈顶元素操作。
3)将中缀表达式转换成后缀表达式。
4)实现后缀表达式的求解。
5)建立一个函数使中缀表达式能够被有效输入。
本程序的关键是中缀表达式转换成后缀表达式对于栈的操作(1)建空栈setStack() 运算的结果是将栈顶元素返回。
(2)清空栈EmptyStack(),可以用于判断栈内元素的有无,在栈顶元素的输出被使用。
(3)入栈push(),出栈pop()和取栈顶元素top()。
2.任务定义1).本演示程序中,利用栈将输入的中缀表达式转换成后缀表达式,并完成其求解过程来达到计算表达式的目的。
2).演示程序以用户和计算机的对话方式执行,即在计算机终端上显示"提示信息"之后,由用户在键盘上输入演示程序中需要输入的数据,以“回车符”为结束标志。
相应的输入数据和运算结果显示在其后。
3).程序执行的命令包括:1)输入任意一个整数表达式;2)是否继续。
4).测试数据输入一个整数表达式:3+(5*8-9)输出:后缀表达式:3 5 8 *9 -+结果为:34继续?(y/n)二、数据结构的选择和概要设计算术表达式中各数据元素间存在一种线性关系,设计的数据类型如下:#define MAXNUM 50typedef int DataType;typedef struct {DataType s[MAXNUM];int t;}SeqStack,*PSeqStack;//定义一个类型名为SeqStack的数据类型本算法设计过程中只采用加减乘除等四种运算符,题目要求借助栈完成算法设计,提示中要把中缀表达式转换成后缀表达式计算,因此操作运算包括要建空栈、清空栈、进栈、出栈、取栈顶元素,中缀表达式转换成后缀表达式,后缀表达式的运算等。
将运算符和界限符一起描述为算符,本程序的设计如下:(1)先定义一下数据结构来存储算术表达式。
(2)建空栈setstack(),清空栈。
(3)对栈进行的运算函数,出入栈和取栈顶元素。
(4)中缀表达式转换成后缀表达式的函数its()。
(5)后缀表达式计算函数。
(6)设计存放后缀表达式的队列。
(7)主函数main(),使得整个程序完整进行。
三、详细设计和编码为了实现概要设计中的所有数据类型,对每个操作给出算法。
对主程序和其他模块也都需要写出算法。
1)数据类型#define MAXNUM 50typedef int DataType;typedef struct {DataType s[MAXNUM];int t;}SeqStack,*PSeqStack;//定义一个类型名为SeqStack的数据类型建空栈和其它关于栈的操作这部分为栈的运算问题。
为后面表达式转换和计算做准备。
这方面的知识书上有系统讲到,不需要过多去设计算法。
2)表达式的转换和计算将中缀表达式转换成后缀表达式,顺序扫描中缀算术表达式,当读到数字时直接将起送至输出队列中;当读到运算符时,将栈中所有优先级高于或等于该运算符的运算符弹出,送至输出队列中,再将当前运算符入栈;当读入左括号时,即入栈;当读入右括号时,将靠近栈的第一个左括号上面的运算符依次弹出,送至输出队列中,再删除栈中左括号。
在计算后缀表达式式,最后保存的值是最先取出参与运算,所以要用到栈。
读到数字时直接送至输出队列中:switch(c1) {case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':set =1;suffix[j++]=c1; /*遇到数字输出*/break;当读到左括号时入栈:case '(':set=0;push(ps, c1); /*遇到左括号,入栈*/break;当读入右括号时,将靠近栈的第一个左括号上面的运算符依次弹出,送至输出队列中,再删除栈中左括号:case ')':c2 = ')'; /*遇到右括号把右括号赋值给c2*/while(!EmptyStack(ps)) { /*当栈不为空时*/c2=top(ps); /*遇到右括号取栈顶*/pop(ps); /*出栈*/if(c2 =='(')break; /*遇到左括号时停止出栈*/suffix[j++]=c2; /*c2的值放入后缀表达式中*/}当读到加减乘除号时,栈和后缀表达式的变化。
因为优先级的关系,将加减号同时考虑,乘除号同时考虑。
读到加减号处理时运用算法如下:case '+':case '-':while(!EmptyStack(ps)) { /*当栈不为空时*/c2 = top(ps); /*将栈顶元素赋值给c2*/if(c2 =='+'|| c2 =='-'|| c2 == '*' || c2 == '/') {pop(ps); /*遇到加减号时栈中栈顶元素是加减乘除四种运算符出栈*/suffix[j++] = c2; /*将c2放入后缀表达式中*/}else if(c2=='(')break; /*遇到加减号时栈顶元素是左括号不进行出栈*/}push(ps, c1); /*c1入栈*/break;读到乘除号处理时算法与加减法基本一致,但在if语句时只需考虑c2 == '*' || c2 == '/'。
计算后缀表达式时读到数值时计算sum的值switch(c) {case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':if(set == 1) /*遇到操作数*/sum = sum * 10 + c - '0'; /*sum的计算*/else /*所遇到的不是操作数*/sum = c - '0';/*sum的计算*/set=1;break;考虑遇到空格、制符表和运算符时sum值的入栈情况case ' ':case'\t':case '\n':if (set == 1) {push(ps, sum); /*遇到空格或制表符sum入栈*/set = 0; }break;case '+':case '-':case '*':case '/':if(set == 1) {push(ps, sum); /*遇到运算符时sum入栈*/set = 0; }遇到加减乘除四个运算符时将栈顶和次栈顶元素分别运用所遇到运算符进行运算,并将运算结果入栈num2 = top(ps); /*栈顶元素赋值给num2*/pop(ps); /*元素出栈*/if(EmptyStack(ps)) { /*当栈为空*/free(ps); /*释放栈内空间*/return 0;}num1 = top(ps); /*栈顶元素赋值给num1*/pop(ps); /*元素出栈*/if(c == '+') { /*c为加号时*/push(ps, num1 + num2); /*num1与num2的和入栈*/}if(c == '-') { /*c为减号时*/push(ps, num1 - num2); /*num1与num2的差入栈*/}if(c == '*'){ /*c为乘号时*/push(ps, num1 * num2); /*num1与num2的积入栈*/}if(c == '/'){ /*c为除号时*/push(ps, num1 / num2); /*num1与num2的商入栈*/}break;default:free(ps);return 0; }}}该部分为程序的核心算法,即将算术表达式的值正确的输出。
4)主函数基本的数据定义,并实现表达式的输入,并调用getline()函数void main() {char c, infix[MAXNUM], suffix[MAXNUM];int result;int flag = 1;while(flag == 1) {printf("请输入任意一个整数算术表达式:\n");getline(infix, MAXNUM); /*调用getline()函数*/if(its(infix, suffix) == 1) {printf("所得后缀为:%s\n", suffix);}else {printf("无效缀!\n");}调用calculateSuffix()函数使程序完整if(calculateSuffix(suffix, &result) == 1){ /*调用calculateSuffix()函数*/ printf("结果为:%d\n", result);}else {printf("非法后缀!\n");}四、上机调试1.编程中遇到的几个问题刚看到题目的时候,我对题意没有理解,运用的普通的方法来完成程序,运行时输入无括号的算术表达式可以正确输出结果,但输入带括号的表达式时输出的结果与运算结果不符。