表达式求值(中序)
实验二 基于栈的中缀算术表达式求值
【实验目的】
1.掌握栈的基本操作算法的实现,包括栈初始化、进栈、出栈、取栈顶元素等。
2.掌握利用栈实现中缀表达式求值的算法。
【实验内容】
问题描述
输入一个中缀算术表达式,求解表达式的值。运算符包括“+”、“-”、“”、“/”、“(”、“)”、“=”,参加运算的数为 double类型且为正数。(要求:直接使用中缀算术表达式进行计算,不能转换为后缀或前缀表达式再进行计算,只考虑二元运算即可。)
输入要求
多组数据,每组数据一行,对应一个算术表达式,每个表达式均以“=”结尾。当表达式只有一个“=”时,输入结束。参加运算的数为 double类型。
输出要求
对于每组数据输出1行,为表达式的运算结果。输出保留两位小数。
输入样例
2+2=
20(4.5-3)=
输出样例
4.00
30.00
【实验提示】
此实验内容即为教材(P53)算法3.4的扩展内容,算法3.4只考虑个位数的运算,不具备拼数功能。拼数功能可以手工编写,也可以借助C语言的库函数atof()函数来完成,其功能是将字符串转换为双精度浮点数( double)。
解决问题的核心思路:
为实现算符优先算法,可以使用两个工作栈:
1.一个称为OPTR,用于寄存运算符
2.另一个称做OPND,用于寄存操作数或运算结果
算法的基本思想:
(1):首先置操作数栈为空栈,表达式的起始符“=”为运算符栈的栈底元素;
(2):依次读入表达式中的每一个字符:
若是操作数则进OPND栈,若是运算符则和OPND栈的栈顶运算符比较
若栈顶运算符<运算符c:运算符c进栈OPND
若栈顶运算符=运算符c:(此时栈顶运算符为“(”,运算符c为”)”)
若栈顶运算符>运算符c:将栈顶运算符出栈,进行运算
(3)直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为“=”)。
完成这个问题需要的知识前提:栈
知识前提:栈的基本运算
顺序栈
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;typedef int Status;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0// ------栈的顺序存储结构表示----------
#define STACK_INIT_SIZE 100 // 存储空间初始分配量
#define STACK_INCREMENT 10 // 存储空间分配增量
typedef int ElemType;
typedef struct {ElemType *base; // 栈底指针ElemType *top; // 栈顶指针int stacksize; // 栈空间大小
} SqStack;void InitStack(SqStack &S)
{// 构造一个空栈Sif(!(S.base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType))))exit(OVERFLOW); // 存储分配失败S.top = S.base;S.stacksize = STACK_INIT_SIZE;
}void DestroyStack(SqStack &S)
{// 销毁栈S,S不再存在free(S.base);S.base = NULL;S.top = NULL;S.stacksize = 0;
}void Push(SqStack &S, ElemType e)
{if(S.top - S.base >= S.stacksize) { // 栈满,追加存储空间S.base = (ElemType *)realloc(S.base, (S.stacksize + STACK_INCREMENT) * sizeof(ElemType));if(!S.base)exit(OVERFLOW); // 存储分配失败S.top = S.base + S.stacksize;S.stacksize += STACK_INCREMENT;}*(S.top)++ = e;
}Status Pop(SqStack &S, ElemType &e)
{// 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;// 否则返回ERRORif(S.top == S.base)return ERROR;e = *--S.top;return OK;
}Status GetTop(SqStack S, ElemType &e)
{// 若栈不空,则用e返回S的栈顶元素,并返回OK;// 否则返回ERRORif(S.top > S.base) {e = *(S.top - 1);return OK;}elsereturn ERROR;
}Status StackEmpty(SqStack S)
{// 若栈S为空栈,则返回TRUE,否则返回FALSEif(S.top == S.base)return TRUE;elsereturn FALSE;
}int main ()
{int n=1;ElemType e,q,temp;int a;SqStack P;InitStack(P);printf("入栈输入:1 ,出栈输入:2 ,得到栈顶元素输入:3 , 判断栈是否为空:4 ,销毁栈:5 \n");while(n){printf("输入操作:"); scanf("%d",&a); switch(a){case 1: printf("入栈操作,输入要入栈的元素:"); scanf("%d",&e);Push(P, e);break;case 2: printf("出栈操作\n"); Pop(P, q);printf("当前出栈的元素的值为:%d\n",q);break;case 3: GetTop(P, temp);printf("输出栈顶元素为 %d \n",temp);break;case 4: if(StackEmpty(P)) printf("当前栈为空\n");else printf("当前栈不空\n"); break;case 5: printf("---正在销毁栈---\n");DestroyStack(P);break;}}}
判断运算符优先级函数
//思路:
1.先实用二维数组存储运算符的优先级
2.使用switch语句对传入的参数进行优先级比较
//根据教科书表3.1,判断两符号的优先关系
char Precede(char t1, char t2){ int i,j; char pre[7][7]={ //运算符之间的优先级制作成一张表格 {'>','>','<','<','<','>','>'}, {'>','>','<','<','<','>','>'}, {'>','>','>','>','<','>','>'}, {'>','>','>','>','<','>','>'}, {'<','<','<','<','<','=','0'}, {'>','>','>','>','0','>','>'}, {'<','<','<','<','<','0','='}}; switch(t1){ case '+': i=0; break; case '-': i=1; break; case '*': i=2; break; case '/': i=3; break; case '(': i=4; break; case ')': i=5; break; case '=': i=6; break; } switch(t2){ case '+': j=0; break; case '-': j=1; break; case '*': j=2; break; case '/': j=3; break; case '(': j=4; break; case ')': j=5; break; case '=': j=6; break; } return pre[i][j];
}
判断字符c是否是运算符
//思路:
1.使用switch语句对c进行判断
//判断c是否为运算符
Status In(OperandType c)
{switch(c){case '+':case '-':case '*':case '/':case '(':case ')':case '=':return TRUE;default:return FALSE;}}
二元运算函数如:+ - * /
//二元运算(a theta b)
ElemType Operate(ElemType a, OperandType theta, ElemType b)
{ElemType c;switch(theta){case '+':c = a + b;break;case '-':c = a - b;break;case '*':c = a * b;break;case '/':c = a / b;break;}return c;
}
表达式求值的全部代码(可以直接运行使用)
#include <stdio.h>
#include <stdlib.h>//函数atof()将字符串转化为一个浮点数值,atoi()将一个字符串转化为一个整数数值
//atol()将一个字符串转化为一个长整数
//malloc()函数
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define STACK_INIT_SIZE 100 //存储空间初始分配量
#define STACKINCREMENT 10 //存储空间分配增量typedef char SElemType;
typedef double ElemType;
typedef char OperandType; //表达式求值的运算类型
typedef int Status;typedef struct
{SElemType *base;SElemType *top;int stacksize;
}SqStack;//构造一个空栈
Status InitStack(SqStack *S)
{S->base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));if(!S->base){printf("内存分配失败!\n");exit(OVERFLOW);}S->top = S->base;S->stacksize = STACK_INIT_SIZE;return OK;
}//若栈不为空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
Status GetTop(SqStack *S, SElemType *e)
{if(S->top == S->base)return ERROR;*e = *(S->top - 1);return OK;
}//插入元素e为新的栈顶元素
Status Push(SqStack *S, SElemType e)
{if(S->top - S->base >= STACK_INIT_SIZE) //栈满, 追加存储空间{S->base = (SElemType *)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(SElemType));if(!S->base){printf("内存分配失败!\n");exit(OVERFLOW);}S->top = S->base + S->stacksize;S->stacksize += STACKINCREMENT;}*S->top++ = e;return OK;
}//若栈不为空,则删除S的栈顶元素,用e返回其值,并返回Ok;否则返回ERROR
Status Pop(SqStack *S, SElemType *e)
{if(S->top == S->base)return ERROR;*e = *--S->top;return OK;
}
//销毁栈S,使其不复存在
Status StackDestroy(SqStack *S)
{free(S->base);S->base = NULL;S->top = NULL;S->stacksize = 0;return OK;
}//清空栈S,保留栈底指针
void ClearStack(SqStack *S)
{S->top = S->base;
}typedef struct
{ElemType *base;ElemType *top;int stacksize;
}SqStack_double;//构造一个空栈
Status InitStack(SqStack_double *S)
{S->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));if(!S->base){printf("内存分配失败!\n");exit(OVERFLOW);}S->top = S->base;S->stacksize = STACK_INIT_SIZE;return OK;
}//若栈不为空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR
Status GetTop(SqStack_double *S, ElemType *e)
{if(S->top == S->base)return ERROR;*e = *(S->top - 1);return OK;
}//插入元素e为新的栈顶元素
Status Push(SqStack_double *S, ElemType e)
{if(S->top - S->base >= STACK_INIT_SIZE) //栈满, 追加存储空间{S->base = (ElemType *)realloc(S->base, (S->stacksize + STACKINCREMENT) * sizeof(ElemType));if(!S->base){printf("内存分配失败!\n");exit(OVERFLOW);}S->top = S->base + S->stacksize;S->stacksize += STACKINCREMENT;}*S->top++ = e;return OK;
}//若栈不为空,则删除S的栈顶元素,用e返回其值,并返回Ok;否则返回ERROR
Status Pop(SqStack_double *S, ElemType *e)
{if(S->top == S->base)return ERROR;*e = *--S->top;return OK;
}
//销毁栈S,使其不复存在
Status StackDestroy(SqStack_double *S)
{free(S->base);S->base = NULL;S->top = NULL;S->stacksize = 0;return OK;
}//清空栈S,保留栈底指针
void ClearStack(SqStack_double *S)
{S->top = S->base;
}//根据教科书表3.1,判断两符号的优先关系
char Precede(char t1, char t2){ int i,j; char pre[7][7]={ //运算符之间的优先级制作成一张表格 {'>','>','<','<','<','>','>'}, {'>','>','<','<','<','>','>'}, {'>','>','>','>','<','>','>'}, {'>','>','>','>','<','>','>'}, {'<','<','<','<','<','=','0'}, {'>','>','>','>','0','>','>'}, {'<','<','<','<','<','0','='}}; switch(t1){ case '+': i=0; break; case '-': i=1; break; case '*': i=2; break; case '/': i=3; break; case '(': i=4; break; case ')': i=5; break; case '=': i=6; break; } switch(t2){ case '+': j=0; break; case '-': j=1; break; case '*': j=2; break; case '/': j=3; break; case '(': j=4; break; case ')': j=5; break; case '=': j=6; break; } return pre[i][j];
}
//判断c是否为运算符
Status In(OperandType c)
{switch(c){case '+':case '-':case '*':case '/':case '(':case ')':case '=':return TRUE;default:return FALSE;}}//二元运算(a theta b)
ElemType Operate(ElemType a, OperandType theta, ElemType b)
{ElemType c;switch(theta){case '+':c = a + b;break;case '-':c = a - b;break;case '*':c = a * b;break;case '/':c = a / b;break;}return c;
}//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和运算数栈,OP为运算符集合
ElemType EvaluateExpression()
{SqStack OPTR;//运算符栈 SqStack_double OPND;//操作数栈 ElemType b,a,result;//double 类型的 OperandType x,theta;//char类型的 char c; //存放有键盘输入的字符串char z[10];InitStack(&OPTR); //初始化运算符栈Push(&OPTR, '='); //=是表达式结束符InitStack(&OPND); //初始化运算数栈c = getchar();GetTop(&OPTR, &x);while(c != '=' || x != '='){if(In(c)) //是7种运算符之一{switch(Precede(x, c)){case '<': //当前已经压栈一个运算符(x)比后一个运算符(c)低时,就将c压栈Push(&OPTR, c);c = getchar();break;case '='://消除小括号 Pop(&OPTR, &x); //脱括号并接收下一字符c = getchar();break;case '>'://将部分表达式求值(两个操作数) Pop(&OPTR, &theta); //退栈并将运算结果压入OPND中Pop(&OPND, &b);Pop(&OPND, &a);Push(&OPND, Operate(a, theta, b));break;}}else if(c >= '0' && c <= '9'||c=='.'){ ElemType sum=0;int i=0;//将字符串中的数字转化为数组存储 while(c >= '0' && c <= '9'||c=='.') {z[i]=c;i++;c = getchar();}z[i]='\0';sum= atof(z);Push(&OPND, sum);}else //c为非法字符{printf("输入表达式有误\n");exit(1);}GetTop(&OPTR, &x);//为了修改switch(Precede(x, c))里面的x; }GetTop(&OPND, &result);//即为表达式求值得到的结果 return result;
}int main()
{printf("请输入算术表达式,负数要用(0-正数)仅支持多位数(double)运算 例如:\n");printf("\t\t\t例如 4+8-9*1+(0-3)+9*1/3=\n");printf("表达式的运算结果为:%.2lf\n", EvaluateExpression());return 0;
}
程序执行的例子