一.实验目的
通过一个具体实际应用例子,加深对数据结构课程的理解,能够综合利用数据结构以及C语言的知识设计程序,应用到实际问题中去。
二.实验题目
常见的小型计算器可以通过输入一个由操作数和操作符组成的表达式计算出结构,设计一个程序模拟上述功能。本实验要求至少建立两个栈和一个运算符优先级比较表,按照运算法优先级的不同操作两个栈,最终实现整个表达式的求值。本程序可以移植到任何一个小型计算器中。
三.实现提示
1.运算符优先级表如下图所示:
|
+ |
- |
* |
/ |
( |
) |
# |
+ |
> |
> |
< |
< |
< |
> |
> |
- |
> |
> |
< |
< |
< |
> |
> |
* |
> |
> |
> |
> |
< |
> |
> |
/ |
> |
> |
> |
> |
< |
> |
> |
( |
< |
< |
< |
< |
< |
= |
|
) |
> |
> |
> |
> |
|
> |
> |
# |
< |
< |
< |
< |
< |
|
= |
2.从键盘上输入的都是按照字符的形式,而实际的计算过程中需要将其转化成对应的操作符和操作数,将其转化可以通过对应的ASCII码表实现,通过查找ASCII码表来找出字符所对应的操作数以及操作符。
3.表达式中可能含有多位数以及带小数的数,对这种情况的处理主要是要通过一个子函数进行,依次读入字符据直到遇到下一个运算符结束,然后整体处理整个字符串,转化成数据。而对于带小数的情况则需要将整数部分和小数部分分开按照前述过程处理,最后再将两部分合并。
四.思考及选做
1.需要注意的是在程序实际运行的时候,对于有小数部分的情况计算的结果会出现截断误差,也就是说计算出的值有舍入情况,注意这一现象,深入理解计算机进行科学计算的本质。
五.我的实现
#include
#include
#include
#define error 0
#define ok 1
#define overflow -1
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OPSETSIZE 7
typedef int Status;
/*
算符间的优先关系
*/
char OPSET[OPSETSIZE]={'+','-','*','/','(',')','#'};
unsigned char Prior[7][7] = {
'>','>','<','<','<','>','>',
'>','>','<','<','<','>','>',
'>','>','>','>','<','>','>',
'>','>','>','>','<','>','>',
'<','<','<','<','<','=',' ',
'>','>','>','>',' ','>','>',
'<','<','<','<','<',' ','='
};
/*
顺序栈结构模板
*/
template
struct SqStack
{
T *top;
T *base;
int stacksize;
};
/*
初始化栈函数模板
*/
template
Status InitStack(T1 &S)
{
S.base=(T2 *)malloc(STACK_INIT_SIZE*sizeof(T2));
if(!S.base) exit (overflow);
S.top=S.base;
S.stacksize=STACK_INIT_SIZE;
return ok;
}
/*
入栈函数模板
*/
template
Status Push(T1 &S,T2 e)
{
if(S.top-S.base>=S.stacksize)
{
S.base=(T2 *)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(T2));
if(!S.base) exit (overflow);
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
*S.top++=e;
return ok;
}
/*
出栈函数模板
*/
template
Status Pop(T1 &S,T2 &e)
{
if(S.top==S.base) return error;
e=*--S.top;
return ok;
}
/*
获取栈顶元素模板
*/
template
T2 GetTop(T1 S)
{
if(S.top==S.base)
return error;
else
return *(S.top-1);
}
/*
判断是否为运算符
*/
Status In(char Test,char* TestOp) {
bool Find=false;
for (int i=0; i< OPSETSIZE; i++) {
if (Test == TestOp[i]) Find= true;
}
return Find;
}
/*
运算
*/
float Operate(float a,unsigned char theta, float b) {
switch(theta) {
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/': return a/b;
default : return 0;
}
}
/*
ReturnOpOrd和precede组合,判断运算符优先级
*/
int ReturnOpOrd(char op,char* TestOp) {
int i;
for(i=0; i< OPSETSIZE; i++) {
if (op == TestOp[i]) return i;
}
return 0;
}
char precede(char Aop, char Bop) {
return Prior[ReturnOpOrd(Aop,OPSET)][ReturnOpOrd(Bop,OPSET)];
}
/*
算术表达式求值的算符优先算法。
设OPTR和OPND分别为运算符栈和运算数栈,OPSET为运算符集合。
*/
float EvaluateExpression() {
SqStack OPTR; // 运算符栈,字符元素
SqStack OPND; // 运算数栈,实数元素
char TempData[20];
float Data,a,b;
char theta,c,x,Dr[2];
InitStack,char> (OPTR);
Push (OPTR, '#');
InitStack ,float>(OPND);
strcpy(TempData,"\0");//将TempData置为空
c=getchar();
while (c!= '#' || GetTop,char>(OPTR)!= '#')
{
if (!In(c, OPSET))
{
Dr[0]=c;
Dr[1]='\0';//存放单个数
strcat(TempData,Dr);//将单个数连到TempData中,形成字符串
c=getchar();
if(In(c,OPSET))//如果遇到运算符,则将字符串TempData转换成实数,入栈,并重新置空
{
Data=(float)atof(TempData);
Push(OPND, Data);
strcpy(TempData,"\0");
}
}
else
{ // 不是运算符则进栈
switch (precede(GetTop,char>(OPTR), c)) {
case '<': // 栈顶元素优先权低
Push(OPTR, c);
c=getchar();
break;
case '=': // 脱括号并接收下一字符
Pop(OPTR, x);
c=getchar();
break;
case '>': // 退栈并将运算结果入栈
Pop(OPTR, theta);
Pop(OPND, b);
Pop(OPND, a);
Push(OPND, Operate(a, theta, b));
break;
}
}
}
return GetTop,float>(OPND);
}
int main()
{
printf("请输入表达式,请以#结束:\n");
printf("%f\n",EvaluateExpression());
system("PAUSE");
return 0;
}