《带括号的表达式求值》课程设计报告.docx
《《带括号的表达式求值》课程设计报告.docx》由会员分享,可在线阅读,更多相关《《带括号的表达式求值》课程设计报告.docx(23页珍藏版)》请在冰豆网上搜索。
![《带括号的表达式求值》课程设计报告.docx](https://file1.bdocx.com/fileroot1/2023-1/10/b1223a7a-3cd6-4838-959c-aaa1f703d2e0/b1223a7a-3cd6-4838-959c-aaa1f703d2e01.gif)
《带括号的表达式求值》课程设计报告
《数据结构与算法分析》课程设计报告
课题名称:
带括号的算术表达式求值
课题负责人名(学号):
0743111298
同组成员名单(角色):
戴维
指导教师:
评阅成绩:
评阅意见:
提交报告时间:
200年月日
带括号的算术表达式求值
软件工程专业
学生戴维指导老师朱宏
一、实验一:
带括号的算术表达式求值
二、实验的目的和要求:
1.采用算符优先数算法,能正确求值表达式;
2.熟练掌握栈的应用;
3.熟练掌握计算机系统的基本操作方法,了解如何编辑、编译、链接和运行一个C++程序;
4.上机调试程序,掌握查错、排错使程序能正确运行。
三、实验的环境:
1.硬件环境:
Intel(R)Celeron(R)MCPU
520@1.60GHz
1.60GHz,0.99Gb内存
2.软件环环境:
操作系统:
MicrosoftWindowsXP
Professinal版本2002
编译系统版本:
MicroSoftVisualC++6.0
包括操作系统,编译系统的版本的特点,编辑软件特点等。
四、算法描述:
对于带有括号的算术表达式有以下的运算法则:
1.先乘方,再乘除,最后加减。
2.同级运算从左到右。
3.先括号内,再括号外。
而运算符号的优先级别如下表所示:
运算符
=
()
+-
*/%
^
优先级
1
2
3
4
5
具体实现如下:
1.先建立两个堆栈,一个是操作符堆栈,一个为操作数堆栈。
并且将这两个堆栈先清空,然后在操作符号堆栈当中放入一个“=”,以便在后面方便判断表达式是否结束。
2.从输入流当中读取一个字符,循环执行下面的操作:
去出操作符号堆栈的栈顶元素,如果栈顶元素是不是“=”并且如果当前的字符也是“=”的时候,那么表示表达式已经结束了,当前操作数堆栈的栈顶元素就是表达式的值。
如果当前字符不是操作符,就将当前字符放回到输入流当中,读取操作数,并且将操作数加入到操作数堆栈当中,继续读入下一个字符。
如果当前字符是操作符就进行下面的操作:
.如果当前字符不是“+”或者“-”,则在当前字符前面加一个“0”放入到操作数栈当中。
如果当前字符和操作符的栈顶元素不匹配,例如当前字符是“(”,而栈顶字符“)”,显示错误信息。
如果操作符栈的栈顶元素是“(”并且当前字符是“)”,则从操作符栈当中取出,去掉括号,然后继续读入下面的字符。
如果当前字符是“(”,或者操作符栈顶元素的优先级别比当前字符低,则将当前字符放入到操作符栈当中。
继续读入下一个字符。
如果操作符栈顶元素的优先级别等于或者大于当前字符的优先级别,那么就取出操作数栈的RIGHT和LEFT元素,从操作符栈当中取出OP,然后进行操作(LEFT)OP(RIGHT),结果进入到操作数栈当中.
五、源程序清单:
Calculator.h:
template
classCalculator
{
private:
Stackopnd;//建立一个操作数的栈
Stackoptr;//建立一个操作符的栈
boolGetTwoOperands(double&left,double&right);
//从操作数栈当中取出最上面的两个数字
boolDoOperator(charop);
//runthefunction"leftopright"
boolIsOperator(charch);
//判断传入的字符是不是一个操作符
voidGetChar(char&ch);
//从输入流当中读入一个字符
intisp(charop);//堆栈外优先数
inticp(charop);//堆栈内优先数
public:
voidRun();//运行函数
};
template
voidCalculator:
:
Run()
{
optr.clear();//将操作符栈的所有元素清空
opnd.clear();//将操作数栈的所有元素清空
optr.push('=');//先在操作符栈中传入一个‘=’号,为了能够更好的判断运算是否已经
结束
//当从外面的读入的字符是‘=’并且栈顶符号也是‘=’时,运算结束
charch;//临时的一个字符
charpriorChar;//前一个字符
charoptrTop;//操作符栈的栈顶元素
Data_elementoperand;//需要被操作的操作数
charop='0';//定义一个操作数为‘0’,便于操作小数的运算
GetChar(ch);//得到一个字符
optr.top(optrTop);//得到操作符栈的栈顶元素
if(optr.top(optrTop)==underflow)
//如果操作符号栈为空,抛出错误信息
{
cout<<"表达式有错!
"<return;
}
while(optrTop!
='='||ch!
='=')
//通过判断当前的字符和栈顶的字符其中一个不为“=”的时候,
//表示现在运算还没有结束,所以进行下面的操作
{
if(isdigit(ch)||ch=='.')
//如果当先的字符是一个数字或者当前字符是小数点,那么把该字符放回到
输入流当中,
//再把该操作数读入,并且放到操作数栈当中去,把前一个字符赋为0,然后
再继续读入字符
{
cin.putback(ch);
cin>>operand;
opnd.push(operand);
priorChar='0';
GetChar(ch);
}
elseif(!
IsOperator(ch))
//除了数字以外应该只有操作符,现在进行判断,如果不是数字,不是小数
点,
//也不是操作符号,说明输入有错误,打印错误消息,再不断的读入字符,
直到读到表达式结束
{
cout<<"表达式中出现非法字符!
"<while(cin>>ch,ch!
='=');
return;
}
else
{
if((priorChar=='='||priorChar=='(')&&(ch=='+'||ch=='-'))opnd.push
(0);
if(isp(optrTop)//如果操作符栈顶元素的优先级别小于当前操作符号的优先级别就
把当前的
//字符放到操作符栈当中,将当前字符赋值给前一个字符,再读入下一
个字符
{
optr.push(ch);
priorChar=ch;
GetChar(ch);
}
elseif(isp(optrTop)>icp(ch))
//如果操作符栈顶元素的优先级别大于当前操作符号,
//删除操作符栈顶元素,在判断OP是不是操作符号,如果不是就返回
{
optr.top(op);optr.pop();
if(!
DoOperator(op))return;
}
elseif(isp(optrTop)==icp(ch)&&ch==')')
//如果栈内操作符和栈外操作符的优先级别一样的,并且当前的字
符为等号的时候
{
optr.pop();
priorChar=')';
GetChar(ch);
};
}
if(optr.top(optrTop)==underflow)
//如果操作符栈为空的话,输出错误消息
{
cout<<"表达式有错!
"<return;
};
}
if(opnd.top(operand)==underflow||optr.pop()==underflow)
//如果操作数字栈为空或者是操作符号在删除了栈顶元素厚为空,输出错误信息
{
cout<<"表达式有错!
"<return;
}
else
//删除操作数栈的栈顶元素,如果再删除操作符栈栈顶元素成功删除或者能够成功删除
//操作数栈的栈顶元素,输出错误信息
{
opnd.pop();
if(opnd.pop()==success||optr.pop()==success)
{
cout<<"表达式有错!
"<return;
}
cout<return;
}
};
template
intCalculator:
:
isp(charop)
//栈外操作符的优先级判断
{
intresult;
switch(op)
{
case'=':
result=0;
break;
case'(':
result=1;
break;
case'^':
result=7;
break;
case'*':
case'/':
case'%':
result=5;
break;
case'+':
case'-':
result=3;
break;
case')':
result=8;
}
returnresult;
};
template
//操作符栈内优先级的判断
intCalculator:
:
icp(charop)
{
intresult;
switch(op)
{
case'=':
result=0;
break;
case'(':
result=8;
break;
case'^':
result=6;
break;
case'*':
case'/':
case'%':
result=4;
break;
case'+':
case'-':
result=2;
break;
case')':
result=1;
}
returnresult;
};
template
boolCalculator:
:
GetTwoOperands(double&x,double&y)
//从操作数栈当中得到两个数字,如果操作数字栈或者操作符栈的元素少于两个的时候输出错误信息
{
if(opnd.empty())
{
cout<<"表达式有错!
"<returnfalse;
}
opnd.top(y);opnd.pop();
if(opnd.empty())
{
cout<<"表达式有错!
"<returnfalse;
}
opnd.top(x);opnd.pop();
returntrue;
};
template
boolCalculator:
:
DoOperator(charop)
//判断符号,进行相应的操作
{
Data_elementx,y;
boolresult=GetTwoOperands(x,y);
if(result==true)
{
switch(op)
{
case'+':
opnd.push(x+y);
break;
case'-':
opnd.push(x-y);
break;
case'*':
opnd.push(x*y);
break;
case'/':
if(y==0)
{
cout<<"除数为零!
"<returnfalse;
}
opnd.push(x/y);
break;
case'%':
if((long)y==0)
{
cout<<"除数为零!
"<returnfalse;
}
opnd.push((long)x%(long)y);
break;
case'^':
opnd.push(pow(x,y));
}
returntrue;
}
elsereturnfalse;
};
template
voidCalculator:
:
GetChar(char&ch)
//从输入流当中读入字符
{
cin>>ch;
while(ch==''||ch=='\n')
cin>>ch;
};
template
boolCalculator:
:
IsOperator(charch)
//判断输入的字符是不是操作符
{
if(ch=='='||ch=='('||ch=='^'||ch=='*'||
ch=='/'||ch=='%'||ch=='+'||ch=='-'||ch==')')
returntrue;
else
returnfalse;
};
LK_STACK.h:
template
structNode{
Node_entryentry;//定义一个结点元素
Node*next;//定义一个结点指针
Node();//无参数构造函数
Node(Node_entryitem,Node*add_on=NULL);//含参构造函数
};
template
classStack{
public:
Stack();//无参构造函数
boolempty()const;//判断堆栈是不是为空
Error_codepush(constStack_entry&item);//往堆栈当中传入元素
Error_codepop();//删除堆栈的栈顶元素
Error_codetop(Stack_entry&item)const;//得到堆栈的栈顶元素
voidclear();//清空堆栈的所有元素
~Stack();//析构函数
Stack(constStack&original);//有参数构造函数
voidoperator=(constStack&original);//操作符重载
protected:
Node*top_node;//定义一个指针
};
template
Node:
:
Node()//构造函数
{
next=NULL;
}
template
Node:
:
Node(Node_entryitem,Node*add_on)
//含参数构造函数
{
entry=item;
next=add_on;
}
template
Stack:
:
Stack()
//堆栈的构造函数
{
top_node=NULL;
}
template
boolStack:
:
empty()const
//判断堆栈是不是为空
{
if(top_node==NULL)
returntrue;
else
returnfalse;
}
template
Error_codeStack:
:
push(constStack_entry&item)
//往堆栈中添加元素
{
Node*new_top=newNode(item,top_node);
if(new_top==NULL)returnoverflow;
top_node=new_top;
returnsuccess;
}
template
Error_codeStack:
:
pop()
//删除堆栈的栈顶元素
{
Node*old_top=top_node;
if(top_node==NULL)returnunderflow;
top_node=old_top->next;
deleteold_top;
returnsuccess;
}
template
Error_codeStack:
:
top(Stack_entry&item)const
//得到堆栈的栈顶元素
{
Error_coderesult;
if(empty())
returnunderflow;
else{
item=top_node->entry;
returnsuccess;
}
}
template
voidStack:
:
clear()
//清空整个堆栈
{
while(!
empty())
pop();
}
template
Stack:
:
~Stack()
//析构函数
{
clear();
}
Utility.h:
#include//standardstringoperations
#include//standardiostreamoperations
#include//numericlimits
#include//mathematicalfunctions
#include//fileinputandoutput
#include//characterclassification
#include//dateandtimefunction
#include//coninputandoutput
enumError_code{success,fail,underflow,overflow};
//enumbool{false,true};
Calculator.cpp:
#include"Utility.h"
#include"LK_STACK.H"
#include"Calculator.h"
voidmain()
{
Calculators;
chariscontinue='Y';
while(iscontinue=='Y')
{
cout<<"输入表达式(以等号“=”结束):
"<s.Run();
cout<<"是否继续(Y/N)?
";
cin>>iscontinue;
iscontinue=toupper(iscontinue);
}
}
六、运行结果:
1.一般的整数操作:
3+4*5/2=13
2.小数的计算:
4.25*1+3.25/5=4.9
3.乘方操作:
4^4=256
4.取模运算:
7%3=1
5.负数运算:
(-5)*6/2=15
6.分母为零的检验:
7.一次程序结束后继续下一次:
8.一次程序结束后退出程序:
七、实验运行情况分析(包括算法、运行结果、运行环境等问题的讨论)。
(一)算法分析:
对于带有括号的算术表达式有以下的运算法则:
1.先乘方,再乘除,最后加减。
2.同级运算从左到右。
3.先括号内,再括号外。
而运算符号的优先级别如下表所示:
运算符
=
()
+-
*/%
^
优先级
1
2
3
4
5
具体实现如下:
1.先建立两个堆栈,一个是操作符堆栈,一个为操作数堆栈。
并且将这两个堆栈先清空,然后在操作符号堆栈当中放入一个“=”,以便在后面方便判断表达式是否结束。
2.从输入流当中读取一个字符,循环执行下面的操作:
去出操作符号堆栈的栈顶元素,如果栈顶元素是不是“=”并且如果当前的字符也是“=”的时候,那么表示表达式已经结束了,当前操作数堆栈的栈顶元素就是表达式的值。
如果当前字符不是操作符,就将当前字符放回到输入流当中,读取操作数,并且将操作数加入到操作数堆栈当中,继续读入下一个字符。
如果当前字符是操作符就进行下面的操作:
.如果当前字符不是“+”或者“-”,则在当前字符前面加一个“0”放入到操作数栈当中。
如果当前字符和操作符的栈顶元素不匹配,例如当前字符是“(”,而栈顶字符“)”,显示错误信息。
如果操作符栈的栈顶元素是“(”并且当前字符是“)”,则从操作符栈当中取出,去掉括号,然后继续读入下面的字符。
如果当前字符是“(”,或者操作符栈顶元素的优先级别比当前字符低,则将当前字符放入到操作符栈当中。
继续读入下一个字符。
如果操作符栈顶元素的优先级别等于或者大于当前字符的优先级别,那么就取出操作数栈的RIGHT和LEFT元素,从操作符栈当中取出OP,然后进行操作(LEF