湖南大学数据结构四则运算表达式报告.docx
- 文档编号:6807131
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:15
- 大小:159.62KB
湖南大学数据结构四则运算表达式报告.docx
《湖南大学数据结构四则运算表达式报告.docx》由会员分享,可在线阅读,更多相关《湖南大学数据结构四则运算表达式报告.docx(15页珍藏版)》请在冰豆网上搜索。
湖南大学数据结构四则运算表达式报告
实验报告部分
HUNANUNIVERSITY
课程实习报告
题目:
约瑟夫问题
学生姓名付勇
学生学号201226010603
专业班级计算机科学二班
指导老师李晓红
一、需求分析
1.本程序要求首先输入一组数据进行四则运算,输入的数据是按照中缀表达式的结构输入的,完成初始化后,把中缀表达式转化为后缀表达式(逆波兰表达式)输出,同时输出计算结果。
2.程序的功能将输入的中缀表达式转化为后缀表达式输出,同时输出计算结果;
3.程序的输出就是转化后的后缀表达式以及计算的结果,输出结果间用空格隔开;
4.测试数据:
输入:
21+23*(12-6)//正常的中缀表达式结构输入有数据,有+-*/%()^
21+(12-6)*23
25^12*1+2
2577//数据输入中可以留空格,两个数据中间必须是符合四则运算的数据(+-*/()^)
输出:
接上
后缀表达式为:
2123126-*+//输出结果间用一个空格隔开
计算结果为:
159
后缀表达式为:
21126-23*+
计算结果为:
159
输入非法,程序结束!
输入非法,程序结束!
。
二、概要设计
抽象数据类型
中缀表达式的存入和读取是核心问题,计算只要用到两个临时的栈一个存操作数,一个存运算符。
利用二叉树,根节点存操作符,其他节点存操作数,利用二叉树的遍历可以方便的存入和读出操作数和运算符。
(后序遍历实现后缀表达式)二叉树的ADT与节点的ADT分开定义
ADTBinNode
数据对象:
数和字符
数据关系:
无
基本操作:
intval()//返回结点的数值
VoidsetVal(constElem&)//设置节点的值
inlineBinNode*left()const//获取左结点
inlineBinNode*right()const//获取右结点
voidsetLeft(Node*it)//设置左结点
voidsetRight(Node*it)//设置右结点
BoolisLeaf()//是叶子节点吗?
二叉树
ADTBinTree
数据对象:
D={dI∈BinNode|i=0,1,2….}
数据关系:
若D为空集,则称为空树。
否则:
(1)在D中存在唯一的称为根的数据元素root;
(2)当n>1时,其余结点可分为m(m>0)个互
不相交的有限集T1,T2,…,Tm,其中每一
棵子集本身又是一棵符合本定义的树,
称为根root的子树。
基本操作:
voidprint(BinNode*p)//后续输出二叉树
boolevaluate(BinNode*prt)//计算二叉树一个节点
voidclear_help(BinNode*rt)//删除二叉树
BinNode*build_node(stringx)//构建二叉树
voidcopy(BinNode*&r1,BinNode*r2)//拷贝树
ADTStack
数据对象:
D={ai|ai∈binNode,i=1,2,...,n,n≥0
数据关系:
R1={
约定an端为栈顶,a1端为栈底。
基本操作:
boolpush(constBinNode&item);
boolpop(BinNode&it);
booltopValue(BinNode&it);
intlength();const
算法的基本思想:
(1)输入表达式;
(2)判断表达式是否正确;
(3)利用栈的思想转化中缀表达式,最后得到完整二叉树;
提取表达式输出及计算:
利用后序遍历完成从二叉树中提取后缀表达式,按照逆波兰表达式计算过程,遇到操作数压栈,遇到操作符,栈中弹出两个操作数,做运算,结果压入栈,直到只剩下一个数据为止。
程序的流程
程序由五个模块组成:
(1)初始化模块:
完成中缀表达式的输入;
(2)检测模块:
检测中缀表达式输入是否正确;
(3)转换建树模块:
中缀表达式建树,并利用后序遍历输出树。
(4)计算模块:
利用后缀表达式计算表达式;
(4)输出模块:
输出后缀表达式及计算结果。
三、详细设计
物理数据类型
算法的具体步骤
检测表达式:
依次遍历表达式的每一个字符,判断其是操作符还是运算数,如果是运算数“.”,则判断其前一位和下一位是否是运算数,若不是,则表达式有误,如果字符是“)”,则判断下一位是否为运算符“+-*%^”,若不是,则表达式有误,如果是“(”,则下一位是否为“-”或运算数,若不是,则表达式有误,如果,字符是“+-*%^”,判断其下一位是否为“+-*%/^”,若是,则表达式错误;遍历过程中,记录“(”“)”的数目,判断他们是否相等,若不相等,这表达式错误。
boolisok(stringexp)//判断输入是否正确
{
charcheck;
interror=0,lb=0,rb=0,numofoperand=0,numofoperator=0;
for(intm=0;m { check=exp[m]; if(IsOperand(check)) { if(check=='.') { if(! (exp[m-1]>='0'&&exp[m-1]<='9')&&(exp[m+1]>='0'&&exp[m+1]<='9')) { error++; cout<<"浮点型数据输入有误! ! ! "< } } numofoperand++; } elseif(IsOperator(check)) { if(check==')') { rb++; if(rb>lb) { error++; cout<<"右括号不可能大于左括号! ! ! "< } if(IsOperator(exp[m+1])&&(exp[m+1]=='+'||exp[m+1]=='-'||exp[m+1]=='*'||exp[m+1]=='/'||exp[m+1]=='^'||exp[m+1]==')'||exp[m+1]=='%')) { numofoperator++; m++; if(exp[m]==')') rb++; } elseif(IsOperator(exp[m+1])||IsOperand(exp[m+1])) { error++; cout<<"右括号后不可能直接跟数据或左括号! ! ! "< } } elseif(check=='(') { lb++; if(IsOperator(exp[m+1])&&exp[m+1]=='(') { m++; lb++; } elseif(IsOperator(exp[m+1])) { error++; cout<<"左括号后运算符只能跟左括号! ! ! "< } } else { numofoperator++; if(IsOperator(exp[m+1])&&exp[m+1]=='(') { m++; lb++; } elseif(IsOperator(exp[m+1])) { error++; cout<<"非括号的运算符不能直接接非括号运算符! ! ! "< } } } else { error++; cout< ! ! "< } } if((error==0)&&(lb==rb)&&(numofoperand! =0)&&(numofoperator! =0)) returntrue; else returnfalse; } 建树: 算法利用两个临时的栈,一个存操作数,一个存操作符,检测到操作数,建立叶子节点,压入存入操作数栈,遇到操作符,存入操作符栈,每次存操作符时与前一个操作符做运算级别比较,若上一个操作符级别大,则弹出上一个操作符,同时弹出两个操作数建立二叉树,操作符做根节点,在把根节点压入操作数栈,括号做优先级最高处理,遇到右括号(前提是有了左括号和必要的运算式),操作符栈弹出,同时弹出两个操作数,建立二叉树,根节点压入操作数的栈,如果遇到负号,则将0压入操作数栈中,把负号压入操作符中。 伪代码: if(isok(infix)) { for(inti=0;i { c=infix[i]; if(i==0&&c=='-')//若开始为负,则把零压入运算数栈,把'-'压入运算符栈 { binary_treetemp; temp.root=build_node("0"); NodeStack.push(temp); OpStack.push('-'); } else if(IsOperand(c))//若c是0~9的字符,检测他后边的是否为0~9的字符,直到不是0~9的字符为止,将他们转换位数字,压入运算数栈中 { stringtempstring=""; tempstring=tempstring+c; while(i+1 { tempstring+=infix[++i]; } binary_treetemp; temp.root=build_node(tempstring); NodeStack.push(temp); } elseif(c=='+'||c=='-'||c=='/'||c=='*'||c=='^'||c=='%')//若c为运算符 { if(OpStack.empty())//运算符栈为空,将该字符压入栈中 OpStack.push(c); elseif(OpStack.top()=='(')//如果栈顶为(,将c压入运算符栈中 OpStack.push(c); elseif(TakesPrecedence(c,OpStack.top()))//如果栈顶的操作符优先级小于c的优先级,则将c压入运算符栈中 OpStack.push(c); else { while(! OpStack.empty()&&(TakesPrecedence(OpStack.top(),c)||addition(OpStack.top(),c)))//如果栈顶操作符优先级大于等于c的优先级 { binary_treetemp_tree; stringthisstring=""; thisstring=thisstring+OpStack.top(); OpStack.pop(); etree.root=build_node(thisstring); copy(temp_tree.root,NodeStack.top().root); NodeStack.pop(); etree.root->right_child=temp_tree.root; temp_tree.root=NULL; copy(temp_tree.root,NodeStack.top().root); etree.root->left_child=temp_tree.root; NodeStack.pop(); temp_tree.root=NULL; copy(temp_tree.root,etree.root); NodeStack.push(temp_tree); etree.root=NULL; } OpStack.push(c); } } if(c=='(')//若中间遇到括号,则判断下一位是否为'-',如是,建立数据0的二叉树,并将其压入节点栈中,-压入符号栈中 { OpStack.push(c); if(infix[i+1]=='-') { binary_treetemp; temp.root=build_node("0"); NodeStack.push(temp); OpStack.push('-'); ++i; } } elseif(c==')') { while(OpStack.top()! ='(') { binary_treetemp_tree; stringthisstring=""; thisstring=thisstring+OpStack.top(); OpStack.pop(); etree.root=build_node(thisstring); copy(temp_tree.root,NodeStack.top().root); NodeStack.pop(); etree.root->right_child=temp_tree.root; temp_tree.root=NULL; copy(temp_tree.root,NodeStack.top().root); etree.root->left_child=temp_tree.root; NodeStack.pop(); temp_tree.root=NULL; copy(temp_tree.root,etree.root); NodeStack.push(temp_tree); etree.root=NULL; } OpStack.pop(); } } while(! OpStack.empty()) { binary_treetemp_tree; stringthisstring=""; thisstring=thisstring+OpStack.top(); OpStack.pop(); etree.root=build_node(thisstring); copy(temp_tree.root,NodeStack.top().root); NodeStack.pop(); etree.root->right_child=temp_tree.root; temp_tree.root=NULL; copy(temp_tree.root,NodeStack.top().root); etree.root->left_child=temp_tree.root; NodeStack.pop(); temp_tree.root=NULL; copy(temp_tree.root,etree.root); NodeStack.push(temp_tree); if(! OpStack.empty()) etree.root=NULL; } 后序输出: voidprint(void){print(root);} voidprint(BinNode*p)//后续输出二叉树 { if(p! =NULL) { print(p->left_child); print(p->right_child); cout< } 计算: 若根节点是运算符且左右子树为运算数,则将他们做计算,并将结果保存在根节点中,若不是,则计算其左子树,计算其右子树,直到,左右子树为空。 voidevaluate(void){evaluate(root);} boolevaluate(BinNode*prt)//计算二叉树一个节点 { if(IsOperator(prt->data)&&! IsOperator(prt->left_child->data)&&! IsOperator(prt->right_child->data)) { floatnum=0; floatnum1=atof(prt->left_child->data.c_str()); floatnum2=atof(prt->right_child->data.c_str()); if(prt->data=="+") num=num1+num2; elseif(prt->data=="-") num=num1-num2; elseif(prt->data=="*") num=num1*num2; elseif(prt->data=="/") { if(num2==0.0) { cout<<"除数为零! ! ! 运算出错"; returnfalse; } else num=num1/num2; } elseif(prt->data=="^") num=pow(num1,num2);//externfloatpow(floatx,floaty);用法: #include 计算x的y次幂 elseif(prt->data=="%") { if(num2==0.0) { cout<<"除数为零! ! ! 运算出错"; //system("pause"); returnfalse; } else num=(long)num1%(long)num2; } stringstreambob; bob< stringsuzzy(bob.str()); prt->data=suzzy;//计算机结果给根节点,其左右孩子置空 prt->left_child=NULL; prt->right_child=NULL; } elseif(prt->left_child==NULL&&prt->right_child==NULL); else { evaluate(prt->left_child); evaluate(prt->right_child); evaluate(prt); } returntrue; } 四、时空分析 因为此算法是利用栈和二叉树来实现的,故时间复杂度为O(N)。 五、输入和输出格式 输入//输入表达式 IntroducetheExpression: 输出 输出后续表达式,以及计算结果。 六、用户使用说明 本程序除了实现表达式的检测,正数的加减乘除以外,还实现了小数,负数的幂运算。 六、测试结果
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 湖南大学 数据结构 四则运算 表达式 报告