数据结构课程设计十进制四则运算计算器的设计与实现.docx

上传人:b****5 文档编号:29200284 上传时间:2023-07-21 格式:DOCX 页数:30 大小:103.20KB
下载 相关 举报
数据结构课程设计十进制四则运算计算器的设计与实现.docx_第1页
第1页 / 共30页
数据结构课程设计十进制四则运算计算器的设计与实现.docx_第2页
第2页 / 共30页
数据结构课程设计十进制四则运算计算器的设计与实现.docx_第3页
第3页 / 共30页
数据结构课程设计十进制四则运算计算器的设计与实现.docx_第4页
第4页 / 共30页
数据结构课程设计十进制四则运算计算器的设计与实现.docx_第5页
第5页 / 共30页
点击查看更多>>
下载资源
资源描述

数据结构课程设计十进制四则运算计算器的设计与实现.docx

《数据结构课程设计十进制四则运算计算器的设计与实现.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计十进制四则运算计算器的设计与实现.docx(30页珍藏版)》请在冰豆网上搜索。

数据结构课程设计十进制四则运算计算器的设计与实现.docx

数据结构课程设计十进制四则运算计算器的设计与实现

十进制四则运算计算器的设计与实现

1.问题描述

(1)题目描述:

在以二叉树表示算术表达式的基础上,设计一个十进制的四则运算计算器。

(2)基本要求:

实现整数或浮点数的四则运算。

(3)测试数据:

12-(-4)*((20+3/5)*8/5)*(-4)#=-515.36

-(22.7-4208.3)/((2.4+1.6)*12)+4.4-2.9#=88.7

10-(-3)*((21+3/5)*8/3)*(-2)#=-335.6

2.需求分析

(1)程序实现的功能是从键盘输入有效的表达式,求出其值并输出

(2)程序运行后,会提示用户输入表达式,并判断是否有效,并返回值

3.概要设计

为了实现程序功能,用二叉树存储表达式,然后从二叉树按后序遍历的方式取出数据,进行运算,运算时用堆栈存储数据。

(1)二叉链表的定义

ADTBinaryTree{

//数据对象D:

D是具有相同特性的数据元素的集合。

//数据关系R:

//若D=Φ,则R=Φ,称BinaryTree为空二叉树;

//若D≠Φ,则R={H},H是如下二元关系;

//

(1)在D中存在惟一的称为根的数据元素root,它在关系H下无前驱;

//

(2)若D-{root}≠Φ,则存在D-{root}={D1,Dr},且D1∩Dr=Φ;

//(3)若D1≠Φ,则D1中存在惟一的元素x1,∈H,且存在D1上的关系H1?

H;若Dr≠Φ,则Dr中存在惟一的元素xr,∈H,且存在上的关系Hr?

H;H={,,H1,Hr};

//(4)(D1,{H1})是一棵符合本定义的二叉树,称为根的左子树;(Dr,{Hr})是一棵符合本定义的二叉树,称为根的右子树。

//基本操作:

InitBiTree(&T)

//操作结果:

构造空二叉树T。

DestroyBiTree(&T)

//初始条件:

二叉树T已存在。

//操作结果:

销毁二叉树T。

CreateBiTree(&T,definition)

//初始条件:

definition给出二叉树T的定义。

//操作结果:

按definiton构造二叉树T。

ClearBiTree(&T)

//初始条件:

二叉树T存在。

//操作结果:

将二叉树T清为空树。

BiTreeEmpty(T)

//初始条件:

二叉树T存在。

//操作结果:

若T为空二叉树,则返回TRUE,否则返回FALSE。

BiTreeDepth(T)

//初始条件:

二叉树T存在。

//操作结果:

返回T的深度。

Root(T)

//初始条件:

二叉树T存在。

//操作结果:

返回T的根。

Value(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

返回e的值。

Assign(T,&e,value)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

结点e赋值为value。

Parent(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

若e是T的非根结点,则返回它的双亲,否则返回“空”。

LeftChild(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

返回e的左孩子。

若e无左孩子,则返回“空”。

RightChild(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

返回e的右孩子。

若e无右孩子,则返回“空”。

LeftSibling(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

返回e的左兄弟。

若e是T的左孩子或无左兄弟,则返回“空”。

RightSibling(T,e)

//初始条件:

二叉树T存在,e是T中某个结点。

//操作结果:

返回e的右兄弟。

若e是T的右孩子或无右兄弟,则返回“空”。

InsertChild(T,p,LR,c)

//初始条件:

二叉树T存在,p指向T中某个结点,LR为0或1,非空二叉树c与T不相交且右子树为空。

//操作结果:

根据LR为0或1,插入c为T中p所指结点的左或右子树。

p所指结点的原有左或右子树则成为c的右子树。

DeleteChild(T,p,LR)

//初始条件:

二叉树T存在,p指向T中某个结点,LR为0或1。

//操作结果:

根据LR为0或1,删除T中p所指结点的左或右子树。

PreOrderTraverse(T,visit())

//初始条件:

二叉树T存在,Visit是对结点操作的应用函数。

//操作结果:

先序遍历T,对每个结点调用函数Visit一次且仅一次。

一旦visit()失败,则操作失败。

InOrderTraverse(T,visit())

//初始条件:

二叉树T存在,Visit是对结点操作的应用函数。

//操作结果:

中序遍历T,对每个结点调用函数Visit一次且仅一次。

一旦visit()失败,则操作失败。

PostOrderTraverse(T,visit())

//初始条件:

二叉树T存在,Visit是对结点操作的应用函数。

//操作结果:

后序遍历T,对每个结点调用函数Visit一次且仅一次。

一旦visit()失败,则操作失败。

LevelOrderTraverse(T,visit())

//初始条件:

二叉树T存在,Visit是对结点操作的应用函数。

//操作结果:

层次遍历T,对每个结点调用函数Visit一次且仅一次。

一旦visit()失败,则操作失败。

}ADTBinaryTree

(2)本程序包含的模块

 

4.详细设计

(1)二叉树的二叉链表类型定义

typedefstructBitNode

{

ElemTypedata;

structBitNode*Lchild,*Rchild;//二叉树的左右孩子和父母

}BitNode;

typedefBitNode*BitTree;

(2)树的结构定义

classbinarytree//树的类

{

public:

BinNode*root;//根节点

binarytree(void){root=NULL;}//构造函数

voidprint(void){print(root);}

voidprint(BinNode*p)

{

if(p!

=NULL)

{

print(p->left_child);

print(p->right_child);

cout<data<<"";

}

}

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<<"除数为零运算出错";

return0;

}

else

num=num1/num2;

}

elseif(prt->data=="^")

num=pow(num1,num2);

elseif(prt->data=="%")

{

if(num2==0.0)

{

cout<<"除数为零运算出错";

return0;

}

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);

}

return1;

}

voidclear_help(void)

{

clear_help(root);

}

voidclear_help(BinNode*rt)

{

if(rt!

=NULL)

{

clear_help(rt->left_child);

clear_help(rt->right_child);

deletert;

}

}

}

判断表达式是否正确

booljudge(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]==')'))

{

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]=='('||exp[m+1]=='-')//左括号右边只能是数字或者"-"号

{

m++;

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;

}

5.调试分析

(1)程序将所有的二叉树的子树用binarytree进行创建子树,然后将子树的孩子结点和数据域进行计算,存入上一层树的孩子结点中,从而使算术比较节约时间。

(2)程序时空复杂度分析

判断是否是合格字符的函数,所有用bool定义的函数的时间复杂度都是O

(1)。

构造二叉树binarytree()时间复杂度为O(n)。

主函数main()是递归调用,时间复杂度为O(n)。

6.使用说明

程序运行后将提示输入一个有效的表达式并以“#”号结束,不要输入非数字和算符的字符,否则程序将报错退出。

程序将判断输入的表达式是否合理,如果合理则进行创建二叉树,并且使用二叉树计算表达式的结果并输出。

7.测试

8.遇到的问题及解决

9.

首先是存储的问题:

一开始想从左往右,依次将一个表达式存进去,但是最后发现只适用于单个表达式,不能通用,最后看到书上在二叉树的顺序存储结构中,将二叉树补满,其实每一个叶子结点也是一个孩子为空的双亲结点,于是就采用对每遇到的一个操作数或者操作符,创建子树,再将它作为孩子结点送给它的双亲结点。

1.在取出并且计算的过程中,我一开始的思路是“在二叉树中先序遍历,将数据和算符存在一个栈里面,然后判断是否有2个连续的数据,如果有,则进行计算,如果没有则继续压栈,直到二叉树遍历完后,栈中只剩下一个元素,即最后的计算结果”,但是发现栈中的元素都是一个类型,如果非要这样存,那就得设置一个指示符,判断取出的是算符,还是数据,这样设计起来有些麻烦。

后来又采用的是彭波老师主编的《数据结构》教材,实验二的方法,采用堆栈进行计算,将从二叉树取出来的数据进行分类压栈,数据和算符分别压栈,判断优先权,最终计算出结果。

再后来,我希望能从二叉树的叶子结点进行计算,然后在这个过程中修改二叉树的结构,将一个子树(双亲结点和其对应的叶子(2个孩子)结点)计算的结果存进上面双亲结点的孩子结点,从而在最终的到只有1个结点的二叉树,即最终计算结果。

本程序是第二三中方式的结合,不过更偏向后者。

10.附录(带注释的源程序)

#include

#include

#include

#include

#include

usingnamespacestd;

 

boolIsOperator(stringmystring)//判断字符串是否是运算符

{

if(mystring=="-"||mystring=="+"||mystring=="*"||mystring=="/")

returntrue;

else

returnfalse;

}

boolIsOperator(charops)//判断一个字符是否是运算符

{

if(ops=='+'||ops=='-'||ops=='*'||ops=='/'||ops=='('||ops==')')

returntrue;

else

returnfalse;

}

boolIsOperand(charch)//判断是否是数字

{

if(((ch>='0')&&(ch<='9'))||(ch=='.'))

returntrue;

else

returnfalse;

}

booljudge(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]==')'))

{

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]=='('||exp[m+1]=='-')//左括号右边只能是数字或者"-"号

{

m++;

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;

}

booladdition(charOperatorA,charOperatorB)//A和B的优先级相同时返回TRUE.

{

if(OperatorA==OperatorB||(OperatorA=='*'&&OperatorB=='/')||(OperatorA=='/'&&OperatorB=='*')||(OperatorA=='+'&&OperatorB=='-')||(OperatorA=='-'&&OperatorB=='+'))

returntrue;

else

returnfalse;

}

boolTakesPrecedence(charOperatorA,charOperatorB)//按照优先级用if从最优至最后从上至下排列,从而达到比较A与B的优先级

{

if(OperatorA=='(')

returnfalse;

elseif(OperatorB=='(')

returnfalse;

elseif(OperatorB==')')

returntrue;

elseif(addition(OperatorA,OperatorB))

returnfalse;

elseif((OperatorA=='*')||(OperatorA=='/'))

returntrue;

elseif((OperatorB=='*')||(OperatorB=='/'))

returnfalse;

elseif((OperatorA=='+')||(OperatorA=='-'))

returntrue;

else

returntrue;

}

//****************************************************************************//

classBinNode{

public:

stringdata;

BinNode*left_child;

BinNode*right_child;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 成人教育 > 远程网络教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1