数据结构实验报告 逆波兰表达式
逆波兰表达式、波兰表达式【数据结构与算法】

逆波兰表达式、波兰表达式【数据结构与算法】逆波兰表达式、波兰表达式【数据结构与算法】1.前缀表达式⼜称波兰式,前缀表达式的运算符位于操作数之前。
⽐如:- × + 3 4 5 62.中缀表达式就是常见的运算表达式,如(3+4)×5-63.后缀表达式⼜称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后,⽐如:3 4 + 5 × 6 -⼈类最熟悉的⼀种表达式1+2,(1+2)3,3+42+4等都是中缀表⽰法。
对于⼈们来说,也是最直观的⼀种求值⽅式,先算括号⾥的,然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不⽅便。
然后我们还需明确⼀些概念,下⾯通过我们最熟悉的中缀表达式画出⼀棵语法树来直观认识⼀下前后缀表达式的⽣成。
以A+B*(C-D)-E*F为例:中缀表达式得名于它是由相应的语法树的中序遍历的结果得到的。
上⾯的⼆叉树中序遍历的结果就是A+B*(C-D)-E*F。
前缀表达式是由相应的语法树的前序遍历的结果得到的。
上图的前缀表达式为- + A * B - C D * E F后缀表达式⼜叫做逆波兰式。
它是由相应的语法树的后序遍历的结果得到的。
上图的后缀表达式为:A B C D - * + E F * -下⾯我们关注两个点:1.如何根据⼀个逆波兰表达式求出运算结果?2.如果将⼀个中缀表达式转换成后缀表达式(逆波兰表达式)⼀.通过逆波兰表达式计算结果我们先看⼀个例⼦...后缀表达式3 4 + 5 × 6 -的计算1.从左⾄右扫描,将3和4压⼊堆栈;2.遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做⽐较),计算出3+4的值,得7,再将7⼊栈;3.将5⼊栈;4.接下来是×运算符,因此弹出5和7,计算出7×5=35,将35⼊栈;5.将6⼊栈;6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果。
从上⾯的过程我们如何编写代码实现呢?可以采⽤⼀个辅助的栈来实现计算,扫描表达式从左往右进⾏,如果扫描到数值,则压进辅助栈中,如果扫描到运算符,则从辅助栈中弹出两个数值参与运算,并将结果压进到栈中,当扫描表达式结束后,栈顶的数值就是表达式结果。
逆波兰表达式求值实验报告湖大

HUNAN UNIVERSITY 课程实习报告题目:逆波兰表达式求值学生姓名范舜奕学生学号20100820608专业班级通信6班指导老师吴帆完成日期 2012.04. 07实验二逆波兰表达式求值★问题描述选一个后缀表达式,利用堆栈来计算该表达式的值,同时要效验后缀表达式是否正确★基本要求(1)从键盘中输入一个后缀表达式,该表达式包括加减乘除的操作符,一级正整数作为操作数等(2)用堆栈来表示★输入输出格式输入:在字符界面上输入一个后缀表达式,其中两相邻操作数之间利用空格隔开。
以“#”表示结束。
输出:如果该后缀表达式正确,那么在字符界面上输出其结果,计算结果小数点后面保留两位有效数字。
如果不正确,请在字符界面上输出表达式错误提示★测试用例输入:2 3 * 1 -#输出:5★设计思路◆为了测试需要,应以浮点数存储输入和输出,利用堆栈来实现算法。
栈的抽象数据类型的定义如下:ADT Stack {数据对象:D={a i| a i∈ElemSet, i=1,2,...,n, n≥0 }数据关系:R={<a i-1 , a i >| a i-1 ,a i∈D, i=2,...,n}基本操作:InitStack(&S)操作结果:构造一个空栈SDestoryStack(&S)初始条件:栈S已存在操作结果:栈S被销毁Pop(&S,e)初始条件:栈S已存在且非空操作结果:删除S的栈顶元素,并用e返回其值Push(&S,e)初始条件:栈S存在且非空操作结果:插入元素e为新的栈顶元素StackLength(&S)初始条件:栈S已存在操作结果:返回S的元素的个数,即栈的长度} ADT LinkLiSt◆本程序包含三个基本模块(1)主程序模块:元素进栈、出栈、删除栈顶元素、实现数字元素的运算(2)线性表模块:实现栈的抽象数据类型(3)元素结构单元模块:定义栈每个元素的结构◆算法的基本思想:定义堆栈的抽象数据类型,读取键盘上输入的数据,根据读取的输入调用入栈函数,判断输入的数据是否合法,通过switch_case结构判断输入运算符的种类,转而执行不同的处理代码。
实验三 逆波兰表达式的产生及计算

实验三逆波兰表达式的产生及计算一、实验目的非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
二、实验内容将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。
三、逆波兰表达式的产生及计算实验设计思想及算法◆逆波兰式定义将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。
◆产生逆波兰式的前提中缀算术表达式◆逆波兰式生成的设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
运用以上算法分析表达式(a+b*c)*d的过程如下:当前符号输入区符号栈输出区( a+b*c)*da +b*c)*d (+ *c)*d ( ab c)*d (+ a* )*d (+ abc *d (+* ab) *d (+* abc) *d (+ abc*) d ( abc** abc*+d * abc*+* abc*+dabc*+d(1)构造一个栈,存放运算对象。
(2)读入一个用逆波兰式表示的简单算术表达式。
数据结构课程实验报告_实验7优先队列

HUNAN UNIVERSITY课程实习报告题目:逆波兰表达式问题优先队列与堆学生姓名学生学号指导老师完成日期2015-5-9逆波兰表达式问题实验背景在工资管理软件中,不可避免的要用到公式的定义及求值等问题。
对于数学表达式的计算,虽然可以直接对表达式进行扫描并按照优先级逐步计算,但也可以将中缀表达式转换为逆波兰表达式,这样更容易处理。
基本要求使用二叉树来实现。
实现提示利用二叉树后序遍历来实现表达式的转换,同时可以使用实验3的结果来求解后缀表达式的值。
输入输出格式:输入:在字符界面上输入一个中缀表达式,回车表示结束。
输出:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。
测试用例输入:21+23*(12-6)输出:21 23 12 6 -*+源代码:#include<iostream>#include<string>#include<iomanip>using namespace std;char str[100][15];//由于一个数字可能有多个数字组成int search_1(int start,int end)//寻找优先级最小的'+'或‘-’{int i,count=0,pos=-1;//count用来记录括号的数量,pos用来记录优先级最小的'+'或'-'的位置for(i=start;i<end;i++){if(str[i][0]=='(')count++;else if(str[i][0]==')')count--;else if((str[i][0]=='+' || str[i][0]=='-') && count==0)//无括号时pos=i;//i记录的是优先级最小的'+'或'-'的位置,也就是没有括号,并且在后面的加减运算}return pos;}int search_2(int start ,int end)//寻找优先级最小的‘*’或‘/’的位置{int i,count=0,pos=-1;//count用来记录括号的数量,pos用来记录优先级最小的'+'或'-'的位置for(i=start;i<end;i++){if(str[i][0]==')')count--;else if(str[i][0]=='(')count++;else if((str[i][0]=='*' || str[i][0]=='/') && count==0)pos=i;}return pos;}double turn(char c[]) //将字符串中的数字转换为浮点型{double temp=0;int i;for(i=0;;i++){if(c[i]!='\0')temp=temp*10+c[i]-'0';elsebreak;}return temp;}class Node{public:char data[15];Node* lchild;Node* rchild;Node(){lchild=NULL;rchild=NULL;}};class Bintree{public:Node* subroot;Node* creattree(int start ,int end);//建立二叉树void postorder(Node* subroot); //后续遍历二叉树double calcute(Node* subroot); //计算表达式的结果void destory(Node* subroot); //销毁二叉树,释放空间};Node* Bintree::creattree(int start,int end)//用递归的方法来建立二叉树{int pos=-1;Node* root =new Node;if(end-start==1)strcpy(root->data,str[start]);else{pos=search_1(start,end); //找优先级最低的加减法if(pos==-1)pos=search_2(start,end);//如果没有的话那就找优先级最低的乘除法if(pos==-1)root=creattree(start+1,end-1);else{strcpy(root->data,str[pos]);root->lchild=creattree(start,pos);root->rchild=creattree(pos+1,end);}}return root;}void Bintree::postorder(Node* subroot)//递归的方法后续遍历{if(subroot!=NULL){postorder(subroot->lchild);postorder(subroot->rchild);cout<<subroot->data<<" ";}}void Bintree::destory(Node *subroot){if(subroot!=NULL){destory(subroot->lchild);destory(subroot->rchild);}delete (subroot);}double Bintree::calcute(Node* subroot)//计算表达式的结果{double result;if(subroot->lchild==NULL && subroot->rchild==NULL) //递归出口,返回值{result=turn(subroot->data);return result;}switch(subroot->data[0]){case'+':return calcute(subroot->lchild)+calcute(subroot->rchild);break;case'-':return calcute(subroot->lchild)-calcute(subroot->rchild);break;case'*':return calcute(subroot->lchild)*calcute(subroot->rchild);break;case'/':return calcute(subroot->lchild)/calcute(subroot->rchild);break;}}int main(){char a[100];Bintree tree;Node* subroot;int i=0,count=0;bool flag=0;cout<<"请输入表达式:"<<endl;while(cin>>a){int j=0;while(a[i]!=0){if(a[i]=='+' || a[i]=='-' || a[i]=='/' || a[i]=='*'){if(flag){cout<<"表达式错误"<<endl; //判断表达式是否正确,即是否有多个运算符连续输入goto loop;}str[j++][0]=a[i++];flag=1;}else if(a[i]=='(' || a[i]==')'){str[j++][0]=a[i];if(a[i++]=='(')count++;elsecount--;if(count<0){cout<<"表达式错误"<<endl;//判断括号是否匹配goto loop;}}else{int k=0;while(a[i]!='+' && a[i]!='-' && a[i]!='*' && a[i]!='/' && a[i]!=')' && a[i]!='(' && a[i]!=0 )str[j][k++]=a[i++];j++;flag=0;}}if(count!=0){cout<<"表达式错误"<<endl;goto loop;}subroot=tree.creattree(0,j);tree.postorder(subroot);cout<<endl;cout<<"表达式的值:"<<endl;cout<<fixed<<setprecision(2)<<tree.calcute(subroot)<<endl;tree.destory(subroot);loop:{i=0;count=0;flag=0;}}return 0;}运行结果:优先队列与堆一、需求分析1.本程序可以模拟实现医院排列病人看病的顺序;2.程序要求从键盘输入来看病的病人的顺序和他们的病情的紧急程度,病情越紧急紧急程度的数值越小;3.计算机通过程序将紧急程度按照从小到大的顺序,把看病的病人重新排序,最终得到看病的顺序;4.输入的值每次有两个,病人来的顺序和紧急程度,都是整数,以-1,-1输入作为结束符;测试用例输入1152 33 5420510-1 -1输出23514二、概要设计抽象数据类型最终出列的顺序是按照priority的值从小到大的顺序排列的,所以,我们考虑用所输入的权值构建最小值堆来实现。
逆波兰表达式求值(实验报告及C源码)

逆波兰表达式求值一、需求分析1、从键盘中输入一个后缀表达式,该表示包括加减乘除等操作符,以及正整数作为操作数等。
2、用堆栈来实现3、测试数据输入:2 3 * 1 – #输出:2 3 * 1 -- =5二、概要设计抽象数据类型需要一个浮点数栈来存储还没有计算的浮点数或者运算的结果。
ADT Stack数据成员:int size; int top; //分别用于存储栈大小、栈顶位置float *listArray;//存储浮点型数字的数组成员函数:bool push(float it);bool pop(float& it);bool isEmpty(); //判断栈为空bool isOne();//判断栈是否只有一个元素算法的基本思想1. 逐一扫描字符串,用ascii码进行判断,如果该字符是数字,则利用x=x*10+str[i]-48将数据由字符类型转换为浮点型数据;2. 如果字符是‘.’,则将‘.’转化为小数点,并将‘.’后的数据转化为小数部分;3. 遇到空格前是数据的,将x押入栈;4. 如果该字符是’+’,’-’,’*’或’/’,判断栈里的元素是否少于两个个,如果少于两个,报错;如果大于等于两个,就弹出两个数据,并进行相应的计算;程序的流程输入字符串,程序对字符串依次扫描。
扫描一位,处理一位。
扫描完成后,判断栈里是不是只有一个数据,若是,得到正确结果;若不是,则表达式出错。
三、详细设计物理数据类型用浮点数类型的栈存储运算中要用的数据,需要入栈、出栈,故设计如下的浮点类型的栈:class Stack{private:int size;int top;float *listArray;public:Stack(int sz=20);~Stack();bool push(float it);//入栈bool pop(float& it);//出栈bool isEmpty();//判断栈是否为空bool isOne(); //判断栈里是否只有且仅有一个元素};成员函数的函数体Stack::Stack(int sz) //栈构造函数{size=sz;top=0;listArray=new float[size]; }bool Stack::push(float it) {if(top==size)return false;listArray[top++]=it;return true;}bool Stack::pop(float& it) {if(top==0)return false;it=listArray[--top];return true;}bool Stack::isEmpty() //判断站是否为空{if(top==0)return true;return false;}bool Stack::isOne(){if(top==1)return true;return false;}Stack::~Stack(){delete listArray;}算法的具体步骤用switch语句实现1. 逐一扫描字符串,用ascii码进行判断,如果该字符是数字,则利用x=x*10+str[i]-48将数据由字符类型转换为浮点型数据;2. 如果字符是‘.’,则将‘.’转化为小数点,并将‘.’后的数据转化为小数部分;3. 遇到空格前是数据的,将x押入栈;4. 如果该字符是’+’,’-’,’*’或’/’,判断栈里的元素是否少于两个个,如果少于两个,报错;如果大于等于两个,就弹出两个数据,并进行相应的计算;算法的时空分析因为入栈、出栈的时间复杂度均为Θ(1),所以时间的复杂度主要取决于字符串的长度,空间也同样取决于字符串长度。
湖南大学数据结构试验2逆波兰问题

HUNAN UNIVERSITY 课程实习报告题目:逆波兰问题学生姓名刘乐学生学号20080820208专业班级通信工程2班指导老师朱宁波完成日期2010年4月19日一、需求分析1.本程序要求采用堆栈方法计算表达式的值,同时验证后缀报答是是否正确。
2.从键盘输入一个后缀表达式,该表示包括加减乘除等操作,以及正整数作为操作数等。
3.用堆栈来实现。
4.测试数据二、概要设计抽象数据类型为实现上述程序的功能,应以字符存储用户的输入,以及计算出的结果。
算法的基本思想5.根据题目要求,设计一个堆栈,对输入的字符串即后缀表达式中的数字字符逐个入栈,遇到运算符则出栈对栈顶元素和第二个元素进行运算,栈顶指向运算结果。
其中除数不可以为0。
直到表达式运算完输出结果。
定义如下线性表ADT Stack {数据对象:D={ a i | a i∈ElemSet, i=1,2,...,n, n≥0 }数据关系:R1={ <a i-1 ,a i >|a i-1 ,a i∈D, i=2,...,n }约定a n端为栈顶,a1端为栈底}ADT Stack基本操作:InitStack (&S) (构造空栈)DestroyStack(&S)(销毁栈结构)ClearStack (&S) (栈清空)StackLength(S) (求栈长)StackEmpty (S)(判空)GetTop (S, &e) (求栈顶元素)Push (&S, e) (入栈)Pop (&S, &e) (出栈)StackTraverse (S, visit( ))(遍历栈)本程序包含三个基本模块(1)输入模块:完成后缀表达式的输入。
(2)调用循环模块:调用函数建立堆栈进行出栈入栈操作,并计算表达式值。
(3)输出模块:屏幕上显示出结果。
三、详细设计算法的具体步骤float comp(){ int x;i = 0; top = -1;ch = exp[i];while (ch != '#') //以#判断表达式结束{switch(ch){case '+':stack[top-1]=stack[top-1]+stack[top];top--;break;case '-':stack[top-1]=stack[top-1]-stack[top];top--;break;case '*':stack[top-1]=stack[top-1]*stack[top];top--;break;case '/':if(stack[top] == 0){ printf("除数错误!\n");exit(0);//switch语句判断输入为运算符时则运算栈顶元素和第二个元素,特别的对除数不等于0做出出错处理、。
逆波兰表达式
基本思路:
扫描后缀算术表达式字符串,每次从字符串中读取一个字符, 读到空格不做任何处理,若读到运算符,则表明它的两个操 作数已经在栈中,否则读到的字符必为数字,应把它转换为 一个正整数存入一个变量中,然后把计算或转换得到的正整 数(即该变量的值)压入栈中,依次扫描每个字符并进行上述 处理,直到遇到结束符,表明后缀表达式计算完成,最终结 果保存在栈中,并且栈中只有这一个值。
function rpn() Begin read(ch) while ( ch <> '\n') do begin case (ch) of case ’+’ : r ← pop()+pop() push(r) case ’-’ : r ← pop() r ← pop()-r push(r) case ’*’ : r ← pop()*pop() push(r) case ’/’ : r ← pop() r ← pop()/r push(r) end
前缀表达式的递归定义,就像正常表达式可以递归定义一样。
c (常量) rpn rpn rpn - rpn rpn * rpn rpn / rpn rpn
可以考虑用递归函数来求解。
function rpn() begin read(ch) case ch of case ’+’ case ’-’ case ’*’ case ’/’ case ’ ’ default end end
Hale Waihona Puke : : : : : :return return return return return return
rpn() + rpn() rpn() * rpn() / rpn() ch-’0’
逆波兰实验报告
实验一约瑟夫环问题基本要求需要基于线性表的基本操作来实现约瑟夫问题需要利用数组来实现线性表输入输出格式输入格式:n,m输出格式1:在字符界面上输出这n个数的输出序列输出格式2:将这n个数的输出序列写入到文件中实验原理设编号为1-n的n(n>0)个人按顺时针方向围成一圈.首先第1个人从1开始顺时针报数.报m的人(m 为正整数).令其出列。
然后再从他的下一个人开始,重新从1顺时针报数,报m的人,再令其出列。
如此下去,直到圈中所有人出列为止。
求出列编号序列。
利用数组对每个人排序。
利用while函数找到数到m的人,当第L个人出圈之后,报数,并在用后面的人依次填充。
实验程序#include<iostream>using namespace std;int main(){int A[100],n,m;cout<<"输入总人数和喊到的数字:\n";cin>>n>>m;int i,j,k=n;for(i=0;i<n;i++)A[i]=i+1; //让数组的值从1开始while(k>0){for(j=1;j<m;j++)i=(i+1)%k; //寻找第一个喊到m的人cout<<A[i]<<" ";for(j=i+1;j<k;j++) //从i+1开始继续向后喊数A[j-1]=A[j];k--; //剩余人数}cout<<"\n"<<A[i];cout<<endl;return 0;}。
逆波兰表达式
【课题】若某算术表达式采用后置法表示(即逆波兰表达式) ,请编程计算该表达式 的值。如:表达式(a+b*c)/d-e 用后置法表示为 abc*+d/e-。 【问题描述】 计算用运算符后置法表示的表达式的值。 后缀表达式也称逆波兰表达式, 比中缀表达式计算起来更方便简单些,中缀表达式要计算就存在着括号的匹配问题,所以 在计算表达式值时一般都是先转换成后缀表达式,再用后置法计算表达式的值。如:表达 式(a+b*c)/d-e 用后置法表示应为 abc*+d/e-。
4
ch=exp[0]; while(ch!='#'){ if(!In(ch,OPSET)){//不是运算符则压入栈中 if(exp[i+1]==' '){//未出现连续数字 Push(&OPND,ch-48); i+=2; ch=exp[i]; }//if else{//出现连续数字 s=exp[i++]-48; while(exp[i]>='0'&&exp[i]<='9'){ s=s*10+exp[i++]-48; }//while Push(&OPND,s); s=0; ch=exp[++i]; }//else }//if else{ theta=ch; b=Pop(&OPND); a=Pop(&OPND); Push(&OPND,Operate(a,theta,b)); i+=2; ch=exp[i]; } } return GetTop(&OPND); }//EvaluateExpression_2( 3) 函数调用关系图
编译原理报告四逆波兰式
逆波兰式的产生及计算一、目的与要求1、目的通过上机实习,加深对语法制导翻译原理的理解,掌握将语法分析所识别的语法范畴变换为某种中间代码的语义翻译方法。
2、要求(1)选用目前世界上普遍采用的语义分析方法──语法制导翻译技术。
(2)语义分析对象重点考虑经过语法分析后已是正确的语法范畴,实习重点是语义子程序。
(3)中间代码选用比较常见的形式,例如四元式。
二、背景知识属性文法:A=(G,V,F),其中:G:一个CFG, 属性文法的基础。
V:有穷的属性集:每个属性与一个文法符号相关联,这些属性代表与文法符号相关的语义信息,如:类型、地址、值、代码、符号表内容等等。
属性与变量一样,可以进行计算和传递,属性加工的过程即是语义处理的过程。
属性加工与语法分析同时进行。
属性的表示:标始符(或数),写在相应文法的下边,点记法:E.Val,E.Place,E.Type…。
F:关于属性的属性断言或一组属性的计算规则(称为语义规则)。
断言或语义规则与一个产生式相联,只引用该产生式左端或右端的终结符或非终结符相联的属性。
属性有两类:综合属性:归约型属性,用于“自下而上”传递信息。
继承属性:推导型属性,用于“自上而下”传递信息。
综合属性的例子:非终结符E、T及F都有一个综合属性val,符号digit有一个综合属性,它的值由词法分析器提供。
与产生式L→E对应的语义规则仅仅是打印由E产生的算术表达式的值的一个过程,我们可认为这条规则定义了L的一个虚属性。
某些非终结符加上标是为了区分一个产生式中同一非终结符多次出现。
设表达式为3*5+4,则语义动作打印数值19。
3*5+4的带注释的分析树继承属性的例子:继承属性的自上而下定值(Real id1,id2,id3):Real id1,id2,id3的分析树L-属性文法:一个属性文法称为L-属性文法,如果对于每个产生式A→X1X2…Xn,满足:1、Xj(1≤j≤n)的继承属性仅依赖于下述属性值中的一种:A的继承属性或产生式右部位于Xj左边的符号X1,X2,…,Xj-1的属性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
HUNAN UNIVERSITY 课程实习报告
题目逆波兰表达式求值
学生姓名XX
学生学号
专业班级
指导老师
完成日期
一、需求分析
1.本程序要求对用户输入一个后缀表达式,打印输出其结果。
2.后缀表达式有用户通过键盘输入,其中两相邻操作数之间利用空格隔开,以“#”表达结束。
如果该后缀表达式正确,那么在字符界面上输出其结果,计算结果小数点后面保留两位有效数字,如果不正确,请在字符界面上输出表达式错误提示。
3.测试数据
输入
2 3*1-#
输出
5
二、概要设计
1.抽象数据类型
为实现上述程序的功能,应以一个字符数组存储用户的输入,运算中运用到整数及浮点数。
2.算法的基本思想
根据题目要求,计算后缀表达式,需要用到堆栈来实现。
算法如下:
1)假设此表达式正确从字符串第一个开始扫描,遇到运算数就先转化成为数值然后压入堆栈中,
2)如遇到运算符则弹出堆栈上面的两个元素,并进行对应的运算,将得到的值压入栈中,循环计算,然后往堆栈中压入结果,直到最后一个字符为止。
3)若表达式错误:返回错误提示。
ADT:
Stack{
操作对象:字符,整数,浮点数
基本操作:
Stack(int size);//构造大小为size的栈
~Stack();//释放内存空间
void push(const float& n);//数据进栈
float pop();//数据出栈
int length();//计算栈内元素个数
}
3.程序的流程
程序由三个模块组成:
1)输入模块:输入一个表达式的字符串。
2)计算模块:设计一个计算后缀表达式的函数。
3)输出模块:输出显示计算的结果。
三、详细设计
1.算法的具体设计
算法流程图如下:
2.算法的时间复杂度分析
该算法的时间复杂度O(n)。
四、代码源程序
#include<iostream>
#include<string>
#include<math.h>
using namespace std;
class Stack{ 输入字符串a
a[i]>47&&a[i]<57?
数值进栈
a[i]=' '?
a[i]==42 ||a[i]==43 ||a[i]==45 ||a[i]==47
?
运算结果进栈
输出结果Y
N
a[i]='#' ?
Y
N
private:
int size;
int top;
float *listArray;
public:
Stack(int size=5){//定义构造函数
this->size=size;
top=0;
listArray=new float[size];
}
~Stack(){
delete [] listArray;
}
void push(const float& n){// 入栈
if(top==size)
return ;
listArray[top++]=n;
}
float pop(){// 出栈
if(top==0)
return 0;
else
return listArray[--top];
}
int length(){// 栈内元素个数
return top;
}
};
void nibolan(char *p){
int a=strlen(p);//字符串长度
int t=1,k=0,g=0;//s作为有数的标志,t作为是否为整数的标志,k是记录小数计算的幂级数float in=0,fl=0,x,y;//in 为一个数的整数部分,fl为小数部分,x为第一个数,y为第二个数
Stack it(a);//实例化一个栈对象
for(int i=0;i<a;i++){//循环检查字符串的每一个字符
if(p[0]==46){
cout<<"表达式有误"<<endl;
break;
}
else if(p[i]>47 && p[i]<58){//字符对应的数在48~57的范围是数字
if(t)//若是整数
in=in*10+(p[i]-48);
else//小数
fl=fl+(p[i]-48)*pow(0.1,k++);//pow(x,y)函数计算x的y次幂
}
else if(p[0]!=46 && p[i]==46){//若是小数点则记录t=0
if(t==0){//已记录则跳出
cout<<"表达式有误"<<endl;
break;
}
else{
t=0;//有小数
k=1;
}
}
else if(p[i]==' '){
//第一个数整数部分和小数部分进栈
it.push(in+fl);
//此时无数,复原
in=0;
fl=0;
t=1;
k=0;
}
//若为运算符则令数出栈运算然后再将结果入栈
else if(p[i]==42 ||p[i]==43 ||p[i]==45 ||p[i]==47 ){
//第二个数整数部分和小数部分进栈
it.push(in+fl);
//令第二个和第一个数依次出栈
y=it.pop();
x=it.pop();
if(p[i]=='+')
it.push(x+y);
else if(p[i]=='-')
it.push(x-y);
else if(p[i]=='*')
it.push(x*y);
else if(p[i]=='/'){
if(y==0){
cout<<"分母为0!表达式有误"<<endl;
return ;
}else
it.push(x/y);
}
//复原整数和小数部分,默认无小数
in=0;
fl=0;
t=1;
k=0;
}
else if(p[i]=='#'){//若是#则结束
g=1;
break;
}
}
if(it.length()==1 && g==1){//栈内只有一个数,表达式正确且已结束 cout<<"答案为:"<<it.pop();
}
}
int main(){
char s[30];
cout<<"请输入后缀表达式:"<<endl;
while(gets(s))
nibolan(s);
return 0;
}
五、测试结果
六、实验心得
通过此次实验了解了前缀表达式,中缀表达式以及后缀表达式,并且更加熟悉了栈的算法编写,虽然此次实验过程中遇到了很多问题,出现很多Bug以及逻辑上的程序问题,但最后通过与同学讨论以及自己查询资料探究基本得到了解决,完成了基本的要求,感受到了不仅要在课堂上认真学习课后仍需多实践练习,才能掌握好知识。