算术表达式求值系统

合集下载

c语言算术表达式求值

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语言算术表达式求值

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 语言算术表达式的求值方法有了更加深入的了解。

数据结构课程设计-表达式求值【完整版】

数据结构课程设计-表达式求值【完整版】

XXXXXX大学《数据结构》课程设计报告班级:学号:姓名:指导老师:目录一算术表达式求值一、需求分析二、程序得主要功能三、程序运行平台四、数据结构五、算法及时间复杂度六、测试用例七、程序源代码二感想体会与总结算术表达式求值一、需求分析一个算术表达式就是由操作数(operand)、运算符(operator)与界限符(delimiter)组成得。

假设操作数就是正整数,运算符只含加减乘除等四种运算符,界限符有左右括号与表达式起始、结束符“#”,如:#(7+15)*(23—28/4)#。

引入表达式起始、结束符就是为了方便.编程利用“算符优先法”求算术表达式得值.二、程序得主要功能(1)从键盘读入一个合法得算术表达式,输出正确得结果。

(2)显示输入序列与栈得变化过程。

三、程序运行平台Visual C++6、0版本四、数据结构本程序得数据结构为栈。

(1)运算符栈部分:struct SqStack //定义栈{char *base; //栈底指针char *top; //栈顶指针intstacksize; //栈得长度};intInitStack (SqStack &s) //建立一个空栈S{if (!(s、base= (char *)malloc(50*sizeof(char))))exit(0);s、top=s、base;s、stacksize=50;return OK;}char GetTop(SqStack s,char &e) //运算符取栈顶元素{if (s、top==s、base) //栈为空得时候返回ERROR{ﻩ printf("运算符栈为空!\n");ﻩ return ERROR;}elsee=*(s、top-1); //栈不为空得时候用e做返回值,返回S得栈顶元素,并返回OK returnOK;}int Push(SqStack&s,char e) //运算符入栈{if (s、top—s、base >= s、stacksize)ﻩ{printf("运算符栈满!\n");ﻩs、base=(char*)realloc(s、base,(s、stacksize+5)*sizeof(char));//栈满得时候,追加5个存储空间if(!s、base)exit (OVERFLOW);s、top=s、base+s、stacksize;s、stacksize+=5;}ﻩ*(s、top)++=e;//把e入栈ﻩreturn OK;}int Pop(SqStack &s,char &e) //运算符出栈{if (s、top==s、base) //栈为空栈得时候,返回ERROR{printf("运算符栈为空!\n”);ﻩ return ERROR;}else{ﻩﻩe=*-—s、top;//栈不为空得时候用e做返回值,删除S得栈顶元素,并返回OK return OK;}}int StackTraverse(SqStack&s)//运算符栈得遍历{ﻩchar *t;ﻩt=s、base;ﻩif (s、top==s、base){ﻩ printf(”运算符栈为空!\n”); //栈为空栈得时候返回ERRORreturn ERROR;}while(t!=s、top){ﻩﻩprintf(" %c",*t); //栈不为空得时候依次取出栈内元素t++;ﻩ}return ERROR;}(2)数字栈部分:struct SqStackn//定义数栈{int *base; //栈底指针int*top; //栈顶指针int stacksize; //栈得长度};intInitStackn (SqStackn &s) //建立一个空栈S{s、base=(int*)malloc(50*sizeof(int));if(!s、base)exit(OVERFLOW);//存储分配失败s、top=s、base;s、stacksize=50;return OK;}int GetTopn(SqStackn s,int&e) //数栈取栈顶元素{if(s、top==s、base){printf("运算数栈为空!\n");//栈为空得时候返回ERRORﻩ return ERROR;}elseﻩe=*(s、top-1);//栈不为空得时候,用e作返回值,返回S得栈顶元素,并返回OKreturnOK;}int Pushn(SqStackn &s,int e) //数栈入栈{if(s、top—s、base>=s、stacksize){ﻩﻩprintf("运算数栈满!\n");//栈满得时候,追加5个存储空间ﻩs、base=(int*)realloc (s、base,(s、stacksize+5)*sizeof(int));if(!s、base) exit (OVERFLOW);ﻩs、top=s、base+s、stacksize;//插入元素e为新得栈顶元素s、stacksize+=5;}*(s、top)++=e; //栈顶指针变化returnOK;}int Popn(SqStackn &s,int &e)//数栈出栈{ﻩif (s、top==s、base){ﻩ printf("运算符栈为空!\n");//栈为空栈得视时候,返回ERRORﻩ return ERROR;ﻩ}else{ﻩﻩe=*—-s、top;//栈不空得时候,则删除S得栈顶元素,用e返回其值,并返回OK ﻩreturnOK;}}int StackTraversen(SqStackn &s)//数栈遍历{ﻩint*t;ﻩt=s、base ;ﻩif(s、top==s、base)ﻩ{printf("运算数栈为空!\n”);//栈为空栈得时候返回ERRORﻩ return ERROR;ﻩ}ﻩwhile(t!=s、top)ﻩ{printf(” %d”,*t); //栈不为空得时候依次输出t++;}return ERROR;}五、算法及时间复杂度1、算法:建立两个不同类型得空栈,先把一个‘#’压入运算符栈。

表达式求值(数据结构)

表达式求值(数据结构)

表达式求值(数据结构)表达式求值(数据结构)1.引言在计算机科学中,表达式求值是一项重要的任务。

它涉及解析和计算数学或逻辑表达式,以得出最终结果。

表达式可以包括数字、变量、运算符和函数,通过采用特定的计算规则,我们可以将这些表达式转化为具体的数值或逻辑结果。

2.表达式的基本概念2.1 数字在表达式中,数字是最基本的元素。

可以是整数或浮点数,用于进行算术计算。

2.2 变量变量是用于存储和代表值的符号,它可以在表达式中使用。

变量可以通过赋值操作来获得具体的值,在表达式求值过程中,变量会被相应的数值替换。

2.3 运算符运算符是用于执行特定操作的符号。

常见的算术运算符包括加法(+), 减法(-), 乘法和除法(/)逻辑运算符包括与(&&), 或(--------) 和非(!)在表达式求值中,运算符的优先级和结合性规则是非常重要的。

2.4 函数函数是一段封装了特定功能的代码块,可以接受输入参数并返回一个结果。

在表达式中,函数可以用于处理特定的数据操作或算法。

例如,sin(x) 和cos(x) 是常见的三角函数。

3.表达式求值的步骤3.1 词法分析首先,需要对表达式进行词法分析,将表达式分解为一个个的词法单元,例如数字、变量、运算符和函数等。

词法分析可以使用正则表达式或者逐字符扫描的方式进行。

3.2 语法分析在得到词法单元序列后,需要进行语法分析,根据语法规则验证表达式的结构是否正确。

语法分析可以使用自顶向下的LL(1)分析方法或者自底向上的LR分析方法。

3.3 语义分析一旦表达式的结构验证通过,就需要进行语义分析。

语义分析的任务是根据语法树运用特定的求值规则,将表达式转换为具体的数值或逻辑结果。

在语义分析过程中,需要处理变量的赋值和函数的调用。

4.表达式求值的例子为了更好地理解表达式求值的过程,以下是一个例子:________表达式:________ 2 (3 + 4) ●5 / 24.1 词法分析:________将表达式分解为以下词法单元:________ 数字(2, 3, 4, 5), 运算符(, +, -), 括号(), 除法运算符(/)4.2 语法分析:________根据语法规则验证表达式的结构是否正确,构建语法树:________-/ \\// \\ / \\2 + 5 2/ \\3 44.3 语义分析:________根据语法树使用求值规则,依次计算每个节点的值:________●节点:________ 2 (7) ●5 / 2●节点:________ 2 7 ●5 / 2●节点:________ 14 ●5 / 2●节点:________ 14 ●2.5●最终结果:________ 11.55.附件本文档没有涉及附件。

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))```四、总结算术表达式求值是一项常见的数学运算任务,利用栈这一数据结构来实现求值算法是一种简单有效的方法,它将中缀表达式转化为逆波兰表达式后,可以消除括号并减少运算符的优先级关系,从而提高程序的执行效率。

数据结构-算术表达式求值(含需求分析和源代码)

数据结构-算术表达式求值(含需求分析和源代码)

需求分析(附代码)一、需求分析(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 已存在。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构课程设计报告课设题目:算式表达式求值系统班级: 软件1202姓名:学号:****: **成绩:2013 年1月目录一、需求分析 (2)二、概要设计 (2)(一)设计思想 (2)(二)实现方法 (2)(三)模块整体设计图 (3)(四)函数功能介绍 (3)三、详细设计 (4)(一)数据结构设计 (4)(二)模块接口设计 (4)(三)盒图 (5)四、调试分析 (7)五、用户手册 (7)六、测试结果 (8)七、附录 (9)附录一设计体会 (9)附录二源程序 (9)一、需求分析算式表达式求值是程序设计语言编译中一个最基本的问题。

本次任务要求完成一个四则算式表达式求值系统。

具体需求为:当用户输入一个四则算式(包括加、减、乘、除和括号),如(12+3)*2+9*4,输出其计算结果。

具体要求如下:(一)要实现栈的基本操作算法,包括初始化栈、进栈、出栈等。

(二) 在本程序中,表达式中的元素限定为char型,表达式长度不超过100,表达式以“#”号为结束标志。

(三)要求程序输出表达式的计算结果。

二、概要设计(一)设计思想本次四则算式表达式求值的程序采用的是中缀表达式的求值的方法。

所谓中缀表达式,就是指每个二目运算符在两个运算量的中间,假设所讨论的算术运算符包括:+ 、- 、*、/、%、^(乘方)和括号()。

而本次程序的编写只涉及四则运算(+、-、*、/)和括号()。

设运算规则为:.运算符的优先级为:()> *、/> +、- ;.有括号出现时先算括号内的,后算括号外的,多层括号,由内向外进行;表达式作为一个满足表达式语法规则的串存储,如表达式“3*2^(4+2*2-1*3)-5”,它的的求值过程为:自左向右扫描表达式,当扫描到3*2时不能马上计算,因为后面可能还有更高的运算,正确的处理过程是:需要两个栈:对象栈s1和算符栈s2。

当自左至右扫描表达式的每一个字符时,若当前字符是运算对象,入对象栈,是运算符时,若这个运算符比栈顶运算符高则入栈,继续向后处理,若这个运算符比栈顶运算符低则从对象栈出栈两个运算量,从算符栈出栈一个运算符进行运算,并将其运算结果入对象栈,继续处理当前字符,直到遇到结束符“#”。

根据运算规则,左括号“(”在栈外时它的级别最高,而进栈后它的级别则最低了; 乘方运算的结合性是自右向左,所以,它的栈外级别高于栈内; 就是说有的运算符栈内栈外的级别是不同的。

当遇到右括号“)”时,一直需要对运算符栈出栈,并且做相应的运算,直到遇到栈顶为左括号“(”时,将其出栈,因此右括号“)”级别最低但它是不入栈的。

对象栈初始化为空。

根据以上分析,每个运算符栈内、栈外的级别如下:算符栈内级别栈外级别^ 3 4*、/、% 2 2+、- 1 1( 0 4) -1 -1(二)实现方法由于算符是字符类型,而表达式中的数字为数值类型,如果建立两个栈的结构的话,他们除了数据元素不同,其余操作都是类似的,这样不仅会增加程序的空间开销和执行时间,而且也使程序冗余度较大。

我采用的解决方案是设置一个算符值x来表示算符,+、-、*、/、(、)的算符值依次为:1,2,3,4,5,6,用一个switch-case语句将算符转化为相应的数值,然后再入栈,这样就统一了对象栈和算符栈元素的数据类型。

在将“(”出栈时,要避免将初值0数据多次入栈而导致出错,如2*(3-1)-1,正常情况下在遇到*时,就应该将数字2入对象栈,然后将保存算式中数值的变量a置零,但是当遇到“(”时,又要将数字0入栈,这样就会导致结果出错,所以在用户输入的数据入对象栈之前,应先判断是否为“(”,若为“(”,则不能将数据入对象栈;当遇到“)”时,“(”不能入栈,并且要将前面的“3”,“-”,“1”都依次出栈进行计算,在遇到“(”时,将“(”出栈,但接下来又会遇到“-”,因此又要将数字0入栈,这样也会导致结果出错因此,我用了一个z[Max]数组来存放“(”的算符值,在每次入对象栈之前,都需要判断在z[i-1]的值。

在解决了数据类型问题之后,程序的编写就显得容易多了。

基本的操作包括栈的初始化、入栈、出栈、判空栈以及取栈顶元素,然后按照设计思路编写求四则表达式值的程序,此外还有一个界面程序,通过调用清屏函数system("cls")以及switch-case语句来实现界面的切换。

(三)模块整体设计图(四)函数功能介绍1.主函数void main()功能:调用其他各个函数;2.菜单函数 int menu()功能:构造系统界面;3.算式求值函数void suanshi()功能:求解四则算式表达式之值4.栈初始化函数SeqStack *Init_SeqStack()功能:置空栈5.入栈函数int Push_SeqStack (SeqStack *s, int x)功能:将数据元素入栈6.出栈函数int Pop_SeqStack(SeqStack *s, int *x)功能:将数据元素出栈7.取栈顶元素函数int Top_SeqStack(SeqStack *s)功能:取出栈顶元素并将栈顶指针减一8.判空栈函数int Empty_SeqStack(SeqStack *s)功能:判断是否为空栈三、详细设计(一)数据结构设计1.本系统采用结构体来定义栈,其结构如下:typedef struct{int data[Max];int top;}SeqStack;并且设置了两个栈s1,s2分别表示对象栈和算符栈。

2.定义了一个z[Max]数组用来存放出栈的“(”的算符值,以避免将数据初值0入栈而导致出错。

(二)模块接口设计:1.各函数原型为:void main() /*主函数*/int menu() /*菜单函数*/void suanshi() /*计算四则运算表达式*/ SeqStack *Init_SeqStack() /*栈初始化*/int Push_SeqStack (SeqStack *s, int x) /*入栈*/int Pop_SeqStack(SeqStack *s, int *x) /*出栈*/int Top_SeqStack(SeqStack *s) /*取栈顶元素*/int Empty_SeqStack(SeqStack *s) /*判断是否为空栈*/2.系统界面切换的实现利用清屏函数system("cls")实现屏幕切换,在从本界面返回上一界面时,根据提示输入即可,例如:printf("是否继续查询,输入y或Y继续,输入其他键返回上一菜单\n");scanf("%c",&choice);if(choice=='y'||choice=='Y') suanshi();则输入输入任意键都能返回上一界面,在main()函数中用for的无穷循环语句实现各函数的循环调用,以使各功能能够重复实现,直至用户退出系统为止。

(三)盒图:1.主函数盒图图2 主函数盒图2.菜单函数盒图3.算术求值函数盒图调用清屏函数system(“cls ”)输出请输入一个带有括号的四则运算的算式以#结束:输入一个四则运算表达式存入a1数组中 令p 指针指向a1数组,设置对象栈s1和算符栈s2取第一个字符存入变量c 中 当c 不为空时 ‘0’=<c<=’9’是否 a=a*10+c-'0'‘#’ ‘+’ ‘-’ ‘*’ ‘/’ ‘(’ ‘)’x=0;e2=-1;f=-1 x=1;e2=1;f=1x=2;e2=1;f =1x=3;e2=2;f=2x=4;e2=2;f =2x=5;e2=0;f =4x=6;e2=-1;f=-1 x!=5&&z[i-1]==0是否将a 入对象栈,a=0i++如果算符栈空或者栈外优先级高于栈外,则将算符入栈否则将对象栈中出栈两个数据,算符栈出栈一个算符进行计算,直到栈内优先级高于栈外将中间结果入对象栈 算符栈为空是否跳出循环将算符出栈,若为‘(’,且x=‘)’,则将其出栈,否则修改优先级如果x!=6&&x!=0,则将x 入算符栈,并设置优先级c=*p++输出结果并输出是否继续查询,输入y 或Y 继续,输入其他键返回上一菜单 choice=输入字符,若choice==’y ’||’Y ’,则递归调用suanshi(),否则返回4.入栈函数盒图图5 入栈函数盒图四、调试分析在调试过程中我遇到的问题以及我的采取措施有:(一)我先编写只含有加减的运算表达式,然后把乘除加进来,最后再把括号加进来。

因为加减的优先级相同,所以一刚开始,我并没有用栈来做,而是用数组来做,我设置了一个整数类型的数组用来保存表达式中的数值,一个字符类型的数组用来保存算符,然后从左往右依次计算即可,因此,没有什么大问题。

在将乘除加进来的时候,由于涉及到优先级的问题,因此,我不得不将对象数组和算符数组转换为对象栈和算符栈。

当我把括号加进来的时候,就遇到了将初值0数据多次入栈而导致出错的现象,所以,我设置了一个z[Max]数组用来存放“(”出栈时的值,从而解决了问题。

(二)在接收用户输入的数据的时候,我用了整型数据来接收,这样在做除法运算的时候,就有可能会出现运算结果与预期结果不相符的情况,比如1/2,在本系统中运行的结果为0,但是我们预期的结果应该是0.5。

但是如果将栈中的数据元素定义为实型,当将出栈的元素放入switch-case语句中时,系统又会报错。

由于时间原因,我并没有对此做修改,还是将栈中的数据元素定义为整型,但是这样可能会导致在做除法运算的时候,出现结果不准确的情况,这也是本系统的一个漏洞。

(注:本系统的所有代码都是在windows环境下的Microsoft Visual C++ 6.0编译器中运行的。

)五、用户手册(一)进入系统双击算术表达式求值系统.cpp文件,按compile键(或Ctrl+F5)编译程序,再按BuildExecute键(或Ctrl+F5)运行程序,然后就进入了算术表达式求值系统;也可以直接在Debug中找到算术表达式求值系统.exe文件,然后双击它,直接进入系统。

(二)求表达式之值1.进入系统后,输入“1”,按回车,即进入算式表达式求值界面,若输入了除“1”和“2”以外的其他键,则会出现输入错误的提示信息,再按一次回车将重新回到菜单界面。

2.输入一个表达式以“#”为结束标志,要求输入的所有数据都为整数,且只能输入四则运算的算式,即算式中只含有+、-、*、/以及括号,如输入(12+3)*2+9*4#,按回车,即能得到结果。

3.如果想继续进行计算,则可以输入“y”或“Y”,然后重复步骤2,输入其他键将返回上一菜单。

相关文档
最新文档