算术表达式求值

合集下载

算术表达式的求解

算术表达式的求解

软件综合课程设计算术表达式的求解&车厢调度二〇一四年六月目录算数表达式的求解 (3)一、前言 (3)二、问题陈述 (3)三、需求分析 (3)四、概要设计 (4)五、详细设计和编码 (6)六、上级调试过程 (10)七、总结与心得 (12)八、参考文献 (13)附录(源程序): (13)车厢调度 (20)一、问题陈述 (20)二、问题分析与设计 (20)三、运行结果 (20)四、设计体会与总结 (21)附录(源程序) (21)算数表达式的求解一、前言表达式计算是实现程序设计语言的基本问题之一,也是栈的应用的一个典型例子。

设计一个程序,演示用算符优先法对算术表达式求值的过程。

在计算机中,算术表达式由常量、变量、运算符和括号组成。

由于不同的运算符具有不同的优先级,又要考虑括号,因此,算术表达式的求值不可能严格地从左到右进行。

因而在程序设计时,借助栈实现。

算法输入:一个算术表达式,由常量、变量、运算符和括号组成(以字符串形式输入)。

为简化,规定操作数只能为正整数,操作符为+、-*、/,用#表示结束。

算法输出:表达式运算结果。

算法要点:设置运算符栈和操作数栈辅助分析算符优先关系。

在读入表达式的字符序列的同时,完成运算符和运算数的识别处理,以及相应运算。

二、问题陈述(算数表达式的求解)给定一个算数表达式,通过程序求出最后的结果。

要求如下:1、从键盘输入要求解的算术表达式;2、采用栈结构进行算数表达式的求解过程;3、能够判断算数表达式的正确与否;4、对于错误表达式给出提示;5、对于正确表达时给出最后的结果。

三、需求分析有题目可知,程序要求给定一算数表达式并计算最后的结果,我们知道,在高级语言中,任何一个表达式都是有操作数、运算符和界限符组成。

在计算过程中,还要考虑表达式中有无括号以及左右括号之分。

由于运算符有优先级的高低,因此一个算数表达是不可能总是按顺序执行。

通过以上可知,可以用栈来实现运算符的优先级完成算术表达式的求解。

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

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

需求分析(附代码)一、需求分析(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)输入的形式:表达式,例如2*(3+4)#;包含的运算符只能有'+' 、'-' 、'*' 、'/' 、'('、')';(2)输出的形式:运算结果,例如Answer is:77.000000;(3)程序所能达到的功能:对表达式求值并输出结果。

二、概要设计:本课程设计需要用到抽象数据类型栈存储表达式。

本部分给出栈的类型定义与表达式求值操作描述。

1、存储结构(顺序栈):typedef struct SqStack{SElemType *base;SElemType *top;int stacksize;}SqStack;2、基本操作:Status InitStack(SqStack &s)操作结果:初始化一个空栈s。

Status GetTop(SqStack s,SElemType &e)初始条件:栈s已存在。

操作结果:得到s的栈顶元素并用e带回。

Status Push(SqStack &s,SElemType e)初始条件:栈s已存在。

操作结果:向栈s中压入元素e。

Status Pop(SqStack &s,SElemType &e)初始条件:栈s已存在‘操作结果:弹出栈s栈顶元素,并用e带回。

Status In(char e)操作结果:判断e是否为7种运算符之一char Precede(char p,char c)操作结果:比较运算符p与运算符c的优先级。

SElemType Operate(SElemType x,char n,SElemType y)操作结果:计算x,y对运算符n的运算结果。

三、详细设计本部分主要给出表达式求值的实现算法1、初始化一个空栈sStatus InitStack(SqStack &s) //{s.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if(!s.base)exit(OVERFLOW);s.top=s.base;s.stacksize=STACK_INIT_SIZE;return OK;}2、读取栈顶元素Status GetTop(SqStack s,SElemType &e){if(s.top==s.base)return ERROR;e=*(s.top-1);return OK;}3、向栈s中压入元素eStatus Push(SqStack &s,SElemType e){if(s.top-s.base>=s.stacksize){s.base=(SElemType*)realloc(s.base,(s.stacksize+STACKINCREMENT)*sizeof(SElemType));if(!s.base)exit(OVERFLOW);s.top=s.base+s.stacksize;s.stacksize+=STACKINCREMENT;}*s.top++=e;return OK;}4、弹出栈顶元素Status Pop(SqStack &s,SElemType &e) //{if(s.top==s.base)exit(OVERFLOW);e=* --s.top;return OK;}5、判断是否为7种运算符之一Status In(char e) / /{switch(e){case '+':case '-':case '*':case '/':case '(':case ')':case '#':return(1);break;default:return(0);}}6、比较两运算符优先级char Precede(char p,char c){ 'switch(p){case '+':case '-':switch(c){case '*':case '/':case '(':return '<';break;default:return '>';break;}break;case '*':case '/':switch(c){case '(':return '<';break;default:return '>';break;}break;case '(':switch(c){case ')':return '=';break;case '#':printf("ERROR!!\n");exit(OK);default:return '<';break;}break;case ')':switch(c){case '(':printf("ERROR!!\n");exit(OK);default:return '>';break;}break;case '#':switch(c){case ')':printf("ERROR!!\n");exit(OK);case '#':return '=';break;default:return '<';break;}break;}}7、四则运算SElemType Operate(SElemType x,char n,SElemType y) {SElemType e;switch(n){case '+':e=x+y;break;case '-':e=x-y;break;case '*':e=x*y;break;case '/':if(y==0){printf("分母不能为0!\n");exit(1);}else{e=x/y;break;}}return e;}8、主函数进行表达式求值void main(){SqStack OPTR,OPND;SElemType p,s,a,b,theta;char c;printf("请输入一个表达式并以'#'结束\n(只包括' +-*/' 和'('')'):\n");InitStack(OPTR);Push(OPTR,'#');InitStack(OPND);c=getchar();GetTop(OPTR,p);while(c!='#'||p!='#'){if(!In(c)){s=c-48;c=getchar();while(c>='0'&&c<='9'){s=s*10+(c-48);c=getchar();}Push(OPND,s);}else{switch(Precede(p,c)){case '<':Push(OPTR,c);c=getchar();break;case '=':Pop(OPTR,s);c=getchar();break;case '>':Pop(OPTR,theta);Pop(OPND,b);Pop(OPND,a);Push(OPND,Operate(a,theta,b));break;}GetTop(OPTR,p);}}//whileprintf("\n\n");GetTop(OPND,p);printf("Answer is:%f\n",p);getch();}四、调试分析1、初始化了一种类型的两个栈,分别用来存放数值和运算符。

算术表达式求值

算术表达式求值
5
出栈
5 4
5 4 3
5 4 3 2
5 4
3 2 1
图3-2 递归调用时线性表状态
3.1.1 栈的定义及其运算
1.栈的定义 . 栈 ( stack)是一种只允许在一端进行插入和删除的线性表, ) 是一种只允许在一端进行插入和删除的线性表, 它是一种操作受限的线性表。 它是一种操作受限的线性表。在表中只允许进行插入和删除的 一端称为栈顶( 一端称为栈顶 ( top), 另一端称为栈底 ) 另一端称为栈底(bottom)。栈的插入 。 操作通常称为入栈或进栈(push),而栈的删除操作则称为出栈 操作通常称为入栈或进栈 , 或退栈(pop)。当栈中无数据元素时,称为空栈。 或退栈 。当栈中无数据元素时,称为空栈。 根据栈的定义可知,栈顶元素总是最后入栈的, 根据栈的定义可知,栈顶元素总是最后入栈的,因而是最先出 栈底元素总是最先入栈的,因而也是最后出栈。 栈;栈底元素总是最先入栈的,因而也是最后出栈。这种表是 按照后进先出( 的原则组织数据的, 按照后进先出(LIFO,last in first out )的原则组织数据的, , 因此,栈也被称为“后进先出”的线性表。 因此,栈也被称为“后进先出”的线性表。 入栈 出栈 图3-3是一 栈的示意图,通常 是一 栈的示意图, top 示栈顶的 , bottom 栈底。 top 栈底。栈顶 动 栈的当前 。
栈顶 top

an
. .
栈底 bottom
a2 a1
图3-3栈的示意图 栈的示意图
2.栈的基本运算 . (1)initStack(s) 初始化:初始化一个新的栈。 ) 初始化:初始化一个新的栈。 栈空判断: 若栈s空 ( 2) empty(s) 栈空判断 : 若栈 空 , 则返回 ) TRUE;否则,返回 ;否则,返回FALSE。 。 入栈:在栈s的顶部插入元素 的顶部插入元素x, (3)push(s,x) 入栈:在栈 的顶部插入元素 , ) 若栈满,则返回FALSE;否则,返回 若栈满,则返回 ;否则,返回TRUE。 。 (4)pop(s) 出栈:若栈s不空,则返回栈顶元素 ) 出栈:若栈 不空, 不空 并从栈顶中删除该元素; 否则, , 并从栈顶中删除该元素 ; 否则 , 返回空元素 NULL。 。 取栈元素:若栈s不空 不空, (5)getTop(s) 取栈元素:若栈 不空,则返回栈 ) 顶元素;否则返回空元素NULL。 顶元素;否则返回空元素 。 (6)setEmpty(s) 置栈空操作:置栈s为空栈。 ) 置栈空操作:置栈 为空栈。 为空栈 栈是一种特殊的线性表, 栈是一种特殊的线性表 , 因此栈可采用顺序存储 结构存储,也可以使用链式存储结构存储。 结构存储,也可以使用链式存储结构存储。

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

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

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、算法:建立两个不同类型得空栈,先把一个‘#’压入运算符栈。

算术表达式求值

算术表达式求值

题目:算术表达式求值问题内容:一个算术表达式是由操作数(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).演示程序以用户和计算机的对话方式执行,即在计算机终端上显示"提示信息"之后,由用户在键盘上输入演示程序中需要输入的数据,以“回车符”为结束标志。

算术表达式求值

算术表达式求值

算术表达式求值 表达式求值是实现程序设计语⾔的基本问题之⼀,也是栈的应⽤的⼀个典型例⼦。

设计⼀个程序,演⽰⽤算符优先法对算术表达式求值的过程 (1)从键盘输⼊任意⼀个语法正确的(中缀)表达式,显⽰并保存该表达式。

(2)利⽤栈结构,把上述(中缀)表达式转换成后缀表达式,并显⽰栈的状态变化过程和所得到的后缀表达式。

(3)利⽤栈结构,对上述后缀表达式进⾏求值,并显⽰栈的状态变化过程和最终结果。

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#define N 100#define M 10char suffix[N]; //后缀表达式char ret[2]; //字符串栈进⾏弹出时的返回值(弹出元素)char tokens[N][M]; //令牌,将中缀表达式分解后的字符串数组char ctokens[N][M]; //令牌,将后缀表达式分解后的字符串数组int count; //tokens令牌的个数int value; //表达式的值int l = 0; //ctokens令牌的个数typedef struct stack1{ //操作符栈int top;char elem[N][2];}stacki;typedef struct stack2{ //操作数栈int top;int elem[N];}stackj;typedef stacki* STACK; //指向操作符栈的指针typedef stackj* DSTACK; //指向操作数栈的指针void toSuffix(char *str); //将中缀表达式转化成后缀表达式int PreParse(char tokens[][M],char *str); //将中缀表达式分解成令牌返回令牌中字符串个数int GetProsity(char *ch); //获得操作符的优先级并返回void push(STACK S,char *opt); //操作符栈的⼊栈char *pop(STACK S); //操作符栈的出栈,并返回出栈元素int IsEmpty(STACK S); //判断操作符栈是否为空void MakeNull(STACK S); //将操作符栈制空void PrintStack(STACK S); //打印操作符栈void dpush(DSTACK S,int opd); //操作符数的⼊栈void dpop(DSTACK S); //操作符数的出栈void PrintStack1(DSTACK S); //打印操作数栈void MakeNull1(DSTACK S); //将操作数栈制空int Evalute(char ctokens[][M]); //计算后缀表达式的值并返回int main(){char str[N];printf("Please input a expression:\n");gets(str); //输⼊所求中缀表达式strtoSuffix(str); //将中缀表达式转化成后缀表达式puts(suffix); //输出转化后的后缀表达式value = Evalute(ctokens); //计算后缀表达式的值printf("%d",value);return0;}void toSuffix(char *str){int i;stacki stacks; //定义⼀个操作符栈stacksSTACK optstack = &stacks; //定义操作符栈指针optstackMakeNull(optstack);count = PreParse(tokens,str);for(i = 0;i < count;i++){if(!(strcmp(tokens[i],"+") && strcmp(tokens[i],"-") && strcmp(tokens[i],"*") && strcmp(tokens[i],"/") && strcmp(tokens[i],"(") && strcmp(tokens[i],")"))){if(IsEmpty(optstack)){push(optstack,tokens[i]);PrintStack(optstack);}else{if(!strcmp(tokens[i],"(")){push(optstack,tokens[i]);PrintStack(optstack);}else if(!strcmp(tokens[i],")")){while(strcmp(optstack->elem[optstack->top],"(")) //循环直到遇见左括号{strcpy(ctokens[l],optstack->elem[optstack->top]);l++;strcat(suffix,pop(optstack));PrintStack(optstack);}pop(optstack); //左括号弹出PrintStack(optstack);}else{if(GetProsity(tokens[i]) > GetProsity(optstack->elem[optstack->top])){push(optstack,tokens[i]);PrintStack(optstack);}else{while(optstack->top < 100){if(GetProsity(tokens[i]) <= GetProsity(optstack->elem[optstack->top])){strcpy(ctokens[l],optstack->elem[optstack->top]);l++;strcat(suffix,pop(optstack));PrintStack(optstack);}else{break;}}push(optstack,tokens[i]);PrintStack(optstack);}}}}else//是数字则直接加到suffix的后⾯{strcpy(ctokens[l],tokens[i]);l++;strcat(suffix,tokens[i]);}}while(optstack->top < 100) //将剩余元素弹出{strcpy(ctokens[l],optstack->elem[optstack->top]);l++;strcat(suffix,pop(optstack));}PrintStack(optstack);}int PreParse(char tokens[][M],char *str){char p[N];char temp[2];int i=0,j = 0,l,k = 0;for(i = 0;i < strlen(str);i++) //删除表达式中的空格{if(str[i] == '') continue;else{p[j] = str[i];j++;}}p[j] = '\0';i = 0;for(j = 0;j < strlen(p);j++){if(p[j] == '+' || p[j] == '-' || p[j] == '*' || p[j] == '/' || p[j] == '(' || p[j] == ')') //运算符转化为字符串 {temp[0] = p[j];temp[1] = '\0';strcpy(tokens[k],temp);}else{for(l = 0;isdigit(p[j]);l++) //得到多位数字的字符串 {tokens[k][l] = p[j];j++;}tokens[k][l] = '\0';j--;}k++;}return k ;}int GetProsity(char *ch){int prosity;if(!(strcmp(ch,"("))){prosity = 0;}if(!(strcmp(ch,"+") && strcmp(ch,"-"))){prosity = 1;}if(!(strcmp(ch,"*") && strcmp(ch,"/"))){prosity = 2;}return prosity;}void push(STACK S,char *opt){if(S->top == 0){return ;}S->top--;strcpy(S->elem[S->top],opt);return ;}char *pop(STACK S){strcpy(ret,S->elem[S->top]);S->top++;return ret;}int IsEmpty(STACK S){if(S->top > N - 1)return1;elsereturn0;}void MakeNull(STACK S){S->top = N ;}void MakeNull1(DSTACK S){S->top = N ;}void PrintStack(STACK S){int i;for(i = N-1;i >= S->top;i--){printf("%s",S->elem[i]);}printf("\n");}void dpush(DSTACK S,int opd){if(S->top == 0){return ;}S->top--;S->elem[S->top] = opd;}void dpop(DSTACK S){S->top++;}void PrintStack1(DSTACK S){int i;for(i = N-1;i >= S->top;i--){printf("%d ",S->elem[i]);}printf("\n");}int Evalute(char ctokens[][M]){int i;int ropd,lopd;int t;stackj stack; //定义⼀个操作数栈DSTACK opdstack = &stack; //初始化操作数栈指针MakeNull1(opdstack);for(i = 0;i < l;i++){if(!strcmp(ctokens[i],"+")) //操作符则弹出两栈内元素进⾏相应运算 {ropd = opdstack->elem[opdstack->top];dpop(opdstack);lopd = opdstack->elem[opdstack->top];dpop(opdstack);t = lopd + ropd;dpush(opdstack,t);PrintStack1(opdstack);}else if(!strcmp(ctokens[i],"-")){ropd = opdstack->elem[opdstack->top];dpop(opdstack);lopd = opdstack->elem[opdstack->top];dpop(opdstack);t = lopd - ropd;dpush(opdstack,t);PrintStack1(opdstack);}else if(!strcmp(ctokens[i],"*")){ropd = opdstack->elem[opdstack->top];dpop(opdstack);lopd = opdstack->elem[opdstack->top];dpop(opdstack);t = lopd * ropd;dpush(opdstack,t);PrintStack1(opdstack);}else if(!strcmp(ctokens[i],"/")){ropd = opdstack->elem[opdstack->top];dpop(opdstack);lopd = opdstack->elem[opdstack->top];dpop(opdstack);t = lopd / ropd;dpush(opdstack,t);PrintStack1(opdstack);}else//操作数⼊栈{dpush(opdstack,atoi(ctokens[i]));PrintStack1(opdstack);}}value = opdstack->elem[opdstack->top];return value;}。

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. 内容:对参与运算的数据(即操作数)可以为整数或实数,运算符(即操作符)为+、-、*、/(加、减、乘、除),^,等二元操作符,另外还可以含有圆括号,这样的表达式,在扫描过程中就可进行正确的运算。

如3+5*2=,正确的计算结果为13(先乘除后加减)。

在扫描表达式时,若读到数据,则将其压入操作数栈;若读到操作符,则将其与操作符栈顶中的操作符比较优先级,若低,则先弹出操作符栈顶操作符,并连续弹出操作数栈上的两个元素,分别作为栈顶操作符的左右操作数加以计算,计算结果再回压入操作数栈,继续比较扫描到的操作符与操作符栈顶上的操作符。

若高,则将扫描到的操作符压入操作符栈。

“=”可作为优先级最低的操作符,放在表达式最后来使用。

利用C++的模板类、模板函数等,编写通用的栈的类定义,使之适用于操作数和操作符,建立操作数栈和操作符栈。

2.要求:在编程中注重流程中出错情况的判断,及时加以捕获(catch)异常,保证程序的正确运行。

3.设计与编码SeqStack.h#ifndef SeqStack_H#define SeqStack_Hconst int StackSize = 15;template<class Datatype>class SeqStack{public:SeqStack();~SeqStack(){}void Push(Datatype x);Datatype Pop();Datatype GetTop();bool Empty();private:Datatype Data[StackSize];int top;};#endifSeqStack.cpp#include"stdafx.h"#include"SeqStack.h"template<class DataType>SeqStack<DataType>::SeqStack(){top = -1;}template<class DataType>void SeqStack<DataType>::Push(DataType x) {if (top == StackSize - 1)throw"overflow";Data[++top] = x;}template<class DataType>DataType SeqStack<DataType>::Pop() {DataType x;if (top == -1)throw"underflow";x = Data[top--];return x;}template<class DataType>DataType SeqStack<DataType>::GetTop() {if (top != -1)return Data[top];/* elsereturn -1;*/}template<class DataType>bool SeqStack<DataType>::Empty(){if (top == -1)return true;elsereturn false;}Jop2.cpp// job2.cpp : 定义控制台应用程序的入口点。

数据结构课程设计之算术表达式求值

数据结构课程设计之算术表达式求值

1【实验题目及要求】[问题描述]一个算术表达式是由操作数(operand)、运算符(operator)和界限符(delimiter)组成的。

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

引入表达式起始、结束符是为了方便。

编程利用“算符优先法”求算术表达式的值。

[基本要求](1)从键盘或文件读入一个合法的算术表达式,输出正确的结果。

(2)显示输入序列和栈的变化过程。

(3)考虑算法的健壮性,当表达式错误时,要给出错误原因的提示。

(4) 实现非整数的处理(可选功能)。

2【源代码(C语言)】#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAXSIZE 20#define OK 1#define ERROR 0#define OVERLOW 0#define YES 1#define NO 0typedefstruct{char * base;char * top;int stacksize; //最大存储量}OPTR; //字符存储栈typedefstruct{float *base;float *top;int stacksize; //最大存储量}OPND; //数值存储栈int InitOptrStack(OPTR *); //字符栈初始化函数int OptrPush(OPTR *, char); //进字符栈操作int OptrPop(OPTR*, char *); //出字符栈操作int OptrEmpty(OPTR ); //判断字符栈是否为空char GetOptrTop(OPTR); //返回字符栈顶元素int InitOpndStack(OPND *); //数值栈初始化函数int OpndPush(OPND *, float); //进数值栈操作int OpndPop(OPND*, float*); //出数值栈操作int OpndEmpty(OPND ); //判断数值栈是否为空int JudgeChar(char); //判断是否为字符float GetFloat(char *); //接收一个数字char Precede(char, char); //判断优先级操作float Caculate(float,float,char);//计算数值{char ch, noMean, ci;float num, number1, number2;OPTR optr;OPND opnd;//system("color 30");InitOptrStack(&optr);InitOpndStack(&opnd);while(1){printf(" 请输入表达式以“#”开始,以“#”结束\n ");do{ch = getchar();}while(ch !='#'); //忽略前面非‘#’字符OptrPush(&optr, ch);ch = getchar();while(ch != '#' || GetOptrTop(optr) != '#'){if(!JudgeChar(ch)){ //如果输入的是数字num = GetFloat( &ch );OpndPush(&opnd, num);else{ //输入的是字符switch(Precede(GetOptrTop(optr),ch)){case'<':OptrPush(&optr,ch); //栈顶优先级低ch = getchar();break;case'=':OptrPop(&optr,&noMean); //左右括号,把左括号出栈ch = getchar ();break;case'>': //栈顶优先级高if(OpndPop(&opnd, &number2) && OpndPop(&opnd,&number1)){OptrPop(&optr, &ci);num = Caculate(number1, number2, ci ); //出栈计算OpndPush(&opnd, num);}else{printf(" 输入过多运算符!\n");system ("PAUSE");exit(0);}break;}//witch}//else}if(opnd.top -opnd.base >= 2){printf(" 俩个括号之间缺少运算符!\n ");system ("PAUSE");exit( 0 );}OpndPop(&opnd,&num); //直接把OPND的栈元素赋值给numprintf(" 运算结果为%.3f\n", num);}system ("PAUSE");}int InitOptrStack(OPTR * OP){OP->base = (char*)malloc((MAXSIZE+1)*sizeof(char));OP->top = OP->base;OP->stacksize = MAXSIZE;return OK;}int OptrPush(OPTR *OP, char ch){*(OP->top) = ch;OP->top++;return OK;}int OptrPop(OPTR *OP, char *ch){if(OP->base == OP->top)return ERROR;else{OP->top--;*ch = *(OP->top);return OK;}}int OptrEmpty(OPTR OP){if(OP.top == OP.base )return YES;elsereturn NO;}char GetOptrTop(OPTR OP){return *(OP.top -1);}int InitOpndStack(OPND * OP){if(!(OP->base = (float*)malloc((MAXSIZE+1)*sizeof(float)))) exit(OVERLOW);OP->top = OP->base;OP->stacksize = MAXSIZE;return OK;}int OpndPush(OPND *OP, float number) {*(OP->top) = number;OP->top++;return OK;}int OpndPop(OPND *OP, float* number) {if(OP->top == OP->base)return ERROR;else{OP->top--;*number = *(OP->top);return OK;}}int OpndEmpty(OPND OP){if(OP.top == OP.base )return YES;elsereturn NO;}int JudgeChar(char ch){if(ch>='0'&&ch<= '9')return NO;elsereturn YES;}float GetFloat(char* ch){int i;float num = 0;for( i = 0; *ch>= '0'&& *ch<= '9'; i++){ num = num*10 + *ch - '0';*ch = getchar();}return num;}char Precede(char a, char b){char ch;switch(a){case'+':case'-': if(b == '*' || b == '/' || b == '(')ch = '<';elsech = '>';break;case'*':case'/': if( b == '(')ch = '<';elsech = '>';break;case'(': if(b == ')')ch = '=';elseif(b == '#'){printf(" 缺少反括号\n");system ("PAUSE");exit(0);}elsech = '<';break;case')': if(b == '('){printf(" 两个括号之间没有符号相连!\n");system("PAUSE");exit(0);}ch = '>';break;case'#': if(b == '#')ch = '=';elseif(b == ')'){printf(" 没有左括号!\n ");system("PAUSE");exit(0);}elsech = '<';break;default: printf(" 输入运算符超出范围! \n ");system ("PAUSE");exit(0);break;}return ch;}float Caculate(float number1, float number2, char ci){float num;switch( ci){case'+': num = number1 + number2; break;case'-': num = number1 - number2; break;case'*': num = number1 * number2; break;case'/': num = number1 / number2; break;}return num;}3【算法思想】根据栈的原理,建立数字栈OPND和运算符号栈OPTR,对读入的字符进行判断,存入不同的栈内,每次读入一个字符就把该字符和运算符栈顶的优先级进行比较,然后选择相应的操作,这是这个程序的核心代码,如下:switch(Precede(GetOptrTop(optr),ch)){case '<':OptrPush(&optr,ch); //栈顶优先级低ch = getchar();break;case '=':OptrPop(&optr,&noMean); //左右括号,把左括号出栈ch = getchar ();break;case '>': //栈顶优先级高if(OpndPop(&opnd, &number2) && OpndPop(&opnd, &number1)){OptrPop(&optr, &ci);num = Caculate(number1, number2, ci ); //出栈计算OpndPush(&opnd, num);}else{printf(" 输入过多运算符!\n");system ("PAUSE");exit(0);}break;}//witch4【实现效果】完全可以实现题目的要求,除了下图的错误提示,本程序还可以提示的错误有:输入过多运算符,缺少反括号,两个括号之间缺少运算符相连,缺少左括号,输入的运算符超出范围等提示。

算数表达式求值演示

算数表达式求值演示

变量求解
//变量求值运算 void vEvaluateExpression0()//同常量运算类似 { int n=0; StackChar OPTR; Stackint OPND; char Expression[81],TempData[20],theta,*c,x,Opr[20]; int Data,a,b,d,value; InitStack(OPTR); Push(OPTR, '#'); InitStack(OPND); printf("请输入表达式:\n"); gets(Expression);//输入表达式 print(); strcat(Expression,"#"); c=Expression;
常量的四则运算
while( *c!='#' || (GetTop(OPTR,x),x!='#') ) //判断c是否为结束符若是则执行 循环否则运算结束 { n++;//n表示运算了多少步 Step(OPTR,OPND,n);//显示OPND栈和OPTR栈的内容 if( *c>='0' && *c<='9' ) //判断c是否是数字若是则执行 while( *c>='0' && *c<='9' ) 循环 { int i=0; while( *c>='0' && *c<='9' ) //操作数入桟操作 { TempData[i++]=*c; //将操作数c赋给字符数组TempData[i]数组 c++; } TempData[i]='\0';//字符串结束标志 Data=(int)atof(TempData);//将数组TempData中 的字符转换为数字 printNDoperate(Data);//显示输入运算数字时的 操作(调用printNDoperate函数) Push(OPND, Data);//将Data入栈OPND }

C语言表达式求值.

C语言表达式求值.

实验四算术表达式求值运算器一、实验目的帮助学生熟练掌握栈的基本操作,并通过用算符优先法对表达式求值的过程深刻领会用栈解决实际问题的基本方法。

二、实验内容编写程序实现从键盘终端输入语法正确的算术表达式,计算出表达式的值。

为了避免算符的二义性,可以假设表达式中只包含实型正常数运算符包括加、减、乘、除四种基本运算,可以包含圆括号。

三、实验仪器微型计算机实验用编程语言:Turbo C 2.0,Borland C 3.0等以上版本四、实验原理1、算术四则运算法则:先乘除后加减从左至右先括号内后括号外2、方法:对运算符建立优先关系矩阵,按优先关系对表达式进行处理。

算符:运算符和界符。

根据法则1:对于两个相邻运算符,乘除优先于加减。

根据法则2:乘除优先级相同,加减优先级相同。

相邻两个同级运算符左优先。

根据法则3:“(”前面的运算符优先级低于“(”的优先级。

“(”的优先级低于右边相邻算符。

“)”左边的算符高于“)”的优先级。

由于“(”和“)”必须成对出现,令它们的优先性相同。

为了处理的方便,假设表达式以“#”开始和结束,输入表达式的一般形式为:#表达式#如:#5.3+4.2*(7.6+4.5)#规定开始的“#”的优先性低于所有其它算符,所有其它算符的优先性高于结束的“#”。

根据假设,表达式开始的“#”和结束的“#”必须成对出现,所以也令它们的优先性相同。

对于一个正确的表达式,“)”不可能与“(”相邻,“(”不可能与结束的“#”相邻,开始的“#”不可能与“)”相邻,它们之间没有优先性,程序应具有这种判断能力。

根据上面的讨论,可用表1所示的算符优先关系矩阵来描述算符之间的优先关系,其中,用“>”表示表达式中前一个算符的优先性高于后一个算符的优先性,用“<”表示表达式中前一个算符的优先性低于后一个算符的优先性,用“=”表示表达式中前一个算符的优先性与后一个算符的优先性相同。

若两个算符之间无优先性,用空白表示。

运算符

运算符

(13) int a=2; int b=a++%2; printf("b=%d",b); b= 0
(14) int a=2; int b=++a%2; printf("b=%d",b); b= 1
(15)
int a=2;
int b=(a++)+(a++)+(a++);
printf("b=%d,a=%d",b,a);
Int i=3 j=++i; j=i++;
// j=i+1;j=i // j=i;i=i+1
例:
j=3; k=++j;
//k=4,j=4
j=3;k=j++;
//k=3,j=4
j=3;printf(“%d”,++j); //j=4
j=3;printf(“%d”;j++); //j=3
a=3;b=5;c=(++a)*b; //c=20,a=4
a=(2+6,a*2,a*5);
//a=25
c+=(a=b=3,b=a*c,a+b); //a=3,b=3*20=60,c=c+(a+b)=20+63=83
printf("%d %d %d",a,b,c);
}
例: P32 include<stdio.h> main() { int a=5,b=9,c=4,x,y; y=(x=a+b),(b+c); printf("y=%d,x=%d\n",y,x); }

算法表达式求值问题

算法表达式求值问题

一、问题分析和任务定义实验问题:算术表达式求值:一个算术表达式是由操作数(operand),运算符(operator)和界限符(delimiter)组成的。

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

引入表达式起始、结束符是为了方便。

编程利用“算符优先法”求算术表达式的值。

要求:(1)从键盘读入一个合法的算术表达式,输出正确的结果。

(2)显示输入序列和栈的变化过程。

选作内容:操作数类型扩充到实数。

1、问题分析在带括号的算术表达式中,界限符包括左右括号以及表达式起始、结束符“#”,如“# (7+15)*(23-28/4)#”。

假设运算符只有加、减、乘、除4种,则对一个简单的算术表达式求值的运算规则如下:(1) 从左至右运算表达式。

(2) 先乘、除,后加、减。

(3) 先括号内,后括号外。

为方便描述,将运算符和界限符统称为算符。

这样,算符集有{+,-,*,/,(,),#}。

要求:首先,能够读入一个算术表达式,判断表达式的合法性。

其次,如果表达式是正确的,要能够输出一个正确的结果,并且显示具体实现的每步过程。

2、任务定义要想能够实现这个问题,首先,你要从键盘中输入一个表达式,然后判别这个表达式的格式到底是不是正确的。

这样,要想实现这个问题,可以先把所有不正确的表达式格式全都列举出来当作模板,然后将当前输入的表达式与该模板中各种情况进行一一比较,如果有相同的,则说明当前的表达式格式是不正确的,程序停止继续往下执行,询问是否重新输入,如果接着输入,需再次对输入的表达式进行判别,依照上步操作进行;如果不在输入就退出程序。

当输入的格式是正确的,就进入具体的求值过程。

因为运算符和运算数具体处理的不同,这样,就要对运算符和运算数分别进行处理,不可放在一起,这样可以分别设置一个运算符栈和一个运算数栈来分别存储运算符和运算数。

算术表达式求值算法解析

算术表达式求值算法解析
迭代算法
迭代算法在处理复杂表达式时效率较高,因为避免了重复计算,但在处理简单表达式时,由于需要遍历整个表达 式,效率较低。
算法适用范围比较
递归算法
递归算法适用于处理简单的算术表达式 ,如加减乘除等。
VS
迭代算法
迭代算法适用于处理复杂的算术表达式, 如包含括号、指数、对数等运算的表达式 。
算法优缺点比较
预测分析法的优点是处理效率较高,适用于大规模的算术 表达式处理,但缺点是需要使用大量的栈空间,且对于复 杂的算术表达式处理能力有限。
逆波兰表示法
逆波兰表示法是一种不需要括号来表示运算符优先级的方法,通 过将操作数放在前面,运算符放在后面来表示算术表达式。
逆波兰表示法将算术表达式转换为逆波兰表示形式后,可以直接 从左到右依次读取并计算表达式的值。
高程序的执行效率。例如,通过消除冗余计算、简化表达式等手段来优
化代码。
在数学计算器中的应用
表达式求值
数学计算器需要能够对用户输入的算术表达式进行求值,以便得到计算结果。算术表达式求值算法可以用于实现这一 功能,快速准确地计算表达式的值。
符号计算
数学计算器可能需要支持符号计算,即对包含未知数的算术表达式进行求解。算术表达式求值算法可以用于实现符号 计算,通过迭代和近似方法求解表达式的根或极值等。
多精度计算
在一些情况下,数学计算器需要支持多精度计算,以避免浮点数精度问题。算术表达式求值算法可以用 于实现多精度计算,提供更高的计算精度和可靠性。
在人工智能领域的应用
机器学习
数据推理
在机器学习领域,算术表达式求值算 法可以用于实现特征工程和模型训练 过程中的数值计算。例如,在神经网 络训练中,需要对权重、偏差等参数 进行迭代更新,算术表达式求值算法 可以高效地完成这些计算任务。

表达式求值及符号推导

表达式求值及符号推导

表达式求值及符号推导
本文将围绕表达式的求值及符号推导展开,首先介绍一下表达式求值,表达式求值是一种
数学算法,它通过对一组变量、符号及常量的组合,来求得最终的结果。

表达式可以包含
操作符,如 + 和-,也可以是数学函数,如 sin、cos、tan 和 log。

表达式求值的常见
方法有两种:使用栈的方法或者使用递归的方法。

符号推导就是将状态变量、操作符等符号形式的表达式转化为一个或多个简洁、正确的算
法表达式形式,这就需要我们根据表达式当中的符号、变量等内容进行分析,把表达式转
换为算数表达式供程序进行求值。

这里有两种最基本的推导方法,一是预处理符号表达式,即使用一定规则将表达式转换为更简单的求值格式,这里提到的简化是指转换表达式的方法,而不是算术求值的方法;二是函数代换,函数推导过程通过从表达式当中选出终结符,将它们替换为原子函数,从而得到计算函数。

综上所述,表达式求值是对变量、常量及操作符的一种计算方法,可以使用栈或递归算法
进行,而符号推导则是将不同符号的表达式转换为便于程序计算的算数表达式,多是采用
预处理符号表达式或函数代换的方法,需要我们通过分析推导出适当的算法表达式。

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

将(A+B)*((C-D)*E+F)转换成 (A+B)*((C-D)*E+F)转换成 后缀表达式
AB+CDAB+CD-E*F+*
(A+B)*((C(A+B)*((C-D)*E+F) 栈 输出序列 ( A AB (+ AB+ *(( A B +C *((*((A B +CD *( A B +CDCD*(* A B +CD- E CD*(+ *(+ A B +CD- E* CD*(+ *(+ A B +CD- E*F CD* A B +CD- E*F+ CDA B +CD- E*F+ * CD-
表达式求值是程序设计语言编译中的 一个最基本问题。 一个最基本问题。它的实现方法是栈的一 个典型的应用实例。 个典型的应用实例。 表达式都是由操作数 操作数( )、运 表达式都是由操作数(operand)、运 )、 算符( 算符(operator)和界限符(delimiter)组 ) 界限符( ) 成的。其中操作数可以是常数, 成的。其中操作数可以是常数,也可以是 变量或常量的标识符; 变量或常量的标识符;运算符是算术运算 符 + , - , * , / ;界限符为左右括号和 标识表达式结束的结束符。 标识表达式结束的结束符。
1)假如读出的运算符的优先级大于栈顶运算 ) 符的优先级,则将其压入运算符栈, 符的优先级,则将其压入运算符栈,读中缀表 达式的下一个符号。 达式的下一个符号。 2)若栈顶运算符的优先级比读到的运算符 ) 的优先级高或二者相等, 的优先级高或二者相等,弹出栈顶运算符放入 后缀表达式中,当前读到的运算符入栈; 后缀表达式中,当前读到的运算符入栈; 3)遇到“(”,压入堆栈; 压入堆栈; )遇到“ 4)遇到“)”,把“(”上面的操作符依 )遇到“ 次弹出加到后缀表达式中, 出栈; 次弹出加到后缀表达式中,“(”出栈; 3. 假如读出的是表达式结束符“#”,栈中剩余的 假如读出的是表达式结束符“ , 运算符依次出栈并写入到后缀表达式中, 运算符依次出栈并写入到后缀表达式中,转换 完成。 完成。
算术表达式的表示方法
1. 中缀表达式--运算符在操作数之间 中缀表达式-- --运算符在操作数之间 如: A * B / C 运算规则: 运算规则: (1) 先计算括号内,后计算括号外; 先计算括号内,后计算括号外; (2) 在无括号或同层括号内,先进行乘除运算,后 在无括号或同层括号内,先进行乘除运算, 进行加减运算,即乘除运算的优先级高于加减 进行加减运算, 运算的优先级; 运算的优先级; (3) 同一优先级运算,从左向右依次进行。 同一优先级运算,从左向右依次进行。


后缀表达式求值的方法: 后缀表达式求值的方法:
① 从左到右读入后缀表达式,若读到的是操作 从左到右读入后缀表达式, 将它压入堆栈。 数,将它压入堆栈。 若读到的是运算符, ② 若读到的是运算符,就从堆栈中连续弹出两 个元素,进行相应的运算, 个元素,进行相应的运算,并将结果压入栈 中。 ③ 读入结束符时,栈顶元素就是计算结果。 读入结束符时,栈顶元素就是计算结果。
用计算机来处理中缀表达式比较复杂。 用计算机来处理中缀表达式比较复杂 。 一个中缀表达式中有多少个运算符, 一个中缀表达式中有多少个运算符 , 原 则上就得对表达式扫描多少遍, 则上就得对表达式扫描多少遍 , 才能完 成计算。 成计算。 在编译系统中, 在编译系统中 , 把中缀表达式转换成另 外一种表示方法,即后缀表达式, 外一种表示方法 , 即后缀表达式 , 然后 对后缀式表达式进行处理, 对后缀式表达式进行处理 , 后缀表达式 也称为逆波兰式。 也称为逆波兰式。
练习: 练习: 将表达式 ((a+b)-c*(d+e)((a+b)-c*(d+e)-f)*(g+h) 改写成后缀表达式 ab+cde+*ab+cde+*-f-gh+*
堆栈的应用--十进制数转换为r 堆栈的应用--十进制数转换为 --十进制数转换为r 进制数
首先用十进制整数 x 除以基数 r,得到的整余数 是 r 进制数 y 的最低位 y0,放入堆栈,接着以 x 放入堆栈, 除以 r 的整数商作为被除数,用它除以 r 得到 的整数商作为被除数, 的整余数是 y 的次最低位 y1,放入堆栈;依次 放入堆栈; 类推,直到商为 0 时得到的整余数是 y 的最高 类推, 位ym,放入堆栈,假定 y 共有 m+1 位,则栈顶 放入堆栈, 是最高位,且栈中有 m+1 个 r 进制数。 进制数。 是最高位,
0
自由区
MAXNUM-1
lefttop
righttop
两个栈共享邻接空间 两个栈共享邻接空间的示意图如图所示。左栈 两个栈共享邻接空间的示意图如图所示。 入栈时,栈顶指针加1 右栈入栈时, 入栈时,栈顶指针加1,右栈入栈时,栈顶指 针减1 针减1。
栈的应用——算术表达式求值 栈的应用——算术表达式求值
2. 后缀表达式: 后缀表达式: 1929 年,由波兰逻辑学家(Lukasiewicz)提出。 由波兰逻辑学家(Lukasiewicz)提出。 [例 ]

A * B / C; AB*C/ ;
定义: 定义:运算符紧跟在两个操作数之后的表达式叫后缀 表达式。 表达式。 优点:① 后缀表达式没有括号 优点: ② 不存在优先级的差别 ③ 计算过程完全按照运算符出现的先后次序 进行
中缀表达式转换成后缀表达式
首先设定一个运算符栈, 首先设定一个运算符栈,用来保存扫描中缀表达 式得到的暂不能放入后缀表达式中的运算符。 式得到的暂不能放入后缀表达式中的运算符。 基本思想: 基本思想:从左到右依次读出中缀表达式中的各 个符号(操作数或运算符),每读出一个符号后, ),每读出一个符号后 个符号(操作数或运算符),每读出一个符号后, 根据如下运算规则进行处理: 根据如下运算规则进行处理: 1. 假如是操作数,将其放入后缀表达式中; 假如是操作数,将其放入后缀表达式中; 2. 如果是运算符,则: 如果是运算符, (1) 栈空:运算符放入栈中, ) 栈空:运算符放入栈中, (2) 栈不空:比较当前读到的运算符与栈顶运 ) 栈不空: 算符的优先级
后缀表达式求值的ADL算法: 后缀表达式求值的ADL算法: 算法 算法EPE 算法EPE ( p, n ) EPE1 [初始化] [初始化 初始化] CREATS ( S ) . EPE2 [表达式求值] [表达式求值 表达式求值] FOR i=1 TO n DO IF NOT ( ISOPTOR( P[ i ] )) THEN S ⇐ P[ i ]. ELSE ( y ⇐ S . x ⇐ S. S ⇐ APPLIED(P[ i ], x , y) ) ▌
多栈共享邻接空间
在计算机系统软件中, 在计算机系统软件中,各种高级语言的编 译系统都离不开栈的使用。 译系统都离不开栈的使用。常常一个程序中要 用到多个栈,为了不发生上溢错误, 用到多个栈,为了不发生上溢错误,就必须给 每个栈预先分配一个足够大的存储空间, 每个栈预先分配一个足够大的存储空间,但实 际中很难准确地估计。另一方面, 际中很难准确地估计。另一方面,若每个栈都 预分配过大的存储空间, 预分配过大的存储空间,势必会造成系统空间 紧张。 紧张。若让多个栈共用一个足够大的连续存储 空间, 空间,则可利用栈的动态特性使它们的存储空 间互补。这就是栈的共享邻接空间。 间互补。这就是栈的共享邻接空间。
双向栈在一维数组中的实现 栈的共享中最常见的是两栈的共享。假设两 栈的共享中最常见的是两栈的共享。假设两 个栈共享一维数组stack[MAXNUM],则可以 个栈共享一维数组 , 利用栈的“栈底位置不变, 利用栈的“栈底位置不变,栈顶位置动态变 化”的特性,两个栈底分别为 和 的特性,两个栈底分别为-1和 MAXNUM,而它们的栈顶都往中间方向延 , 因此,只要整个数组stack[MAXNUM] 伸。因此,只要整个数组 未被占满,无论哪个栈的入栈都不会发生上 未被占满, 溢。
中缀表达式
后缀表达式
a+b a+b*c a*b*c+c*d (a+b)*((c(a+b)*((c-d)*e+f)
a b+ a b c *+ ab*c*cd*+ ab+cd–e*f+*
[例] 计算后缀表达式ABC*/DE*+AC*-; 计算后缀表达式ABC*/DE*+AC*-
操作
后缀表达式

—— T1=B*C T2 =A/T1 T3 =D*E T4=T2+T3 T5 =A*C T6 =T4- T5
ABC*/DE*+AC*- =; AT1/DE*+AC*- =; T2 DE*+AC*- =; T2T3 +AC*- =; T4AC*- =; T2 T3 T4AC T4 T5 T6
定义五个谓词和函数 CREATS ( S ):建立一个堆栈 S; ): S ⇐ x : 元素 x 进栈; 进栈; x ⇐ S : 元素 x 出栈; 出栈; APPLIED(P, x , y) :运算符 P 作用于操作数 x 和 y 的结果; 的结果; ISOPTOR( x ) : 若x为运算符时为真,否则为 为运算符时为真, 假
相关文档
最新文档