在编译系统中都必须提供算术表达式求值功能,也是通过栈来实现。下面介绍一个简单的算术表达式求值功能的实现,只能对整数的四则混合运算表达式求值。下图为算法流程图。
- 栈头文件
typedef struct stack
{
DATA data[SIZE+1]; //数据元素
int top; //栈顶
}SeqStack;
SeqStack *SeqStackInit()
{
SeqStack *p;
if(p=(SeqStack *)malloc(sizeof(SeqStack))) //申请栈内存
{
p->top=0; //设置栈顶为0
return p;//返回指向栈的指针
}
return NULL;
}
int SeqStackIsEmpty(SeqStack *s) //判断栈是否为空
{
return(s->top==0);
}
void SeqStackFree(SeqStack *s) //释放栈所占用空间
{
if(s)
free(s);
}
void SeqStackClear(SeqStack *s) //清空栈
{
s->top=0;
}
int SeqStackIsFull(SeqStack *s) //判断栈是否已满
{
return(s->top==SIZE);
}
int SeqStackPush(SeqStack *s,DATA data) //入栈操作
{
if((s->top+1)>SIZE)
{
printf("栈溢出!\n");
return 0;
}
s->data[++s->top]=data;//将元素入栈
return 1;
}
DATA SeqStackPop(SeqStack *s) //出栈操作
{
if(s->top==0)
{
printf("栈为空!");
exit(0);
}
return (s->data[s->top--]);
}
DATA SeqStackPeek(SeqStack *s) //读栈顶数据
{
if(s->top==0)
{
printf("栈为空!");
exit(0);
}
return (s->data[s->top]);
}
- 表达式求值文件
#include<stdio.h>
#include<stdlib.h>
#define SIZE 50
typedef int DATA;
int IsOperator(char c) //检查字符是否为运算符
{
switch(c)
{
case'+':
case'-':
case'*':
case'/':
case'(':
case')':
case'=':
return 1;
break;
default:
return 0;
break;
}
}
在计算表达式时,为了方便判断,增设了一个等号“=”作为表达式的定界符,即表达式以“=”开头,以“=”结束。
在计算表达式的值时,需要比较前后两个运算符的优先级。
int PRI(char oper1,char oper2) //判断两个运算符的优先级
// oper1>oper2返回1
//oper1<oper2返回-1
//oper1=oper2返回0
{
int pri;
switch(oper2) //判断运算符优先级
{
case '+':
case '-':
if(oper1=='('||oper1=='=') //为左括号或表达式开始符号
pri=-1; //返回小于
else
pri=1;
break;
case '*':
case '/':
if(oper1=='*'||oper1=='/'||oper1==')')
pri=1;
else
pri=-1;
break;
case '(':
if(oper1==')') //右括号右侧不能马上出现左括号
{
printf("语法错误!\n");
exit(0);
}else
pri=-1;
break;
case')':
if(oper1=='(')
pri=0;
else if (oper1=='=')
{
printf("括号不匹配!\n");
exit(0);
}else
pri=1;
break;
case '=' :
if(oper1=='(')
{
printf("括号不匹配!\n");
exit(0);
}else if(oper1=='=')
pri=0;
else
pri=1;
break;
}
return pri;
}
该函数中,根据传入的两个运算符进行判断,得到不同的优先级。在主调函数中再根据优先级决定是入栈还是计算。
对于优先级高的运算符,需将运算符两侧的数据进行计算。
int Calc(int a,int oper,int b) //计算两个操作数的结果
{
switch(oper)
{
case'+':return a+b;
case'-':return a-b;
case'*':return a*b;
case'/':
if(b!=0)
return a/b;
else
{
printf("除0溢出!\n");
exit(0);
}
}
}
编写好以上辅助函数就可以编写计算表达式值的函数了
int CalcExp(char exp[]) //表达式计算函数
{
SeqStack *StackOper,*StackData;
int i=0,flag=0;
DATA a,b,c,q,x,t,oper;
StackOper=SeqStackInit(); //初始化两个栈
StackData=SeqStackInit();
q=0;
x='=';
SeqStackPush(StackOper,x); //首先将等号(=)进入操作符栈
x=SeqStackPeek(StackOper); //获取操作符栈的首元素
c=exp[i++];
while(c!='=' || x!='=')
{
if(IsOperator(c)) //若输入的是运算符
{
if(flag){
SeqStackPush(StackData,q);//将操作数入栈
q=0;
flag=0;
}
switch(PRI(x,c)) //判断运算符的优先级
{
case -1:
SeqStackPush(StackOper,c);//运算符进栈
c=exp[i++];
break;
case 0:
c=SeqStackPop(StackOper); //运算符出栈 (抛弃)
c=exp[i++];
break;
case 1:
oper=SeqStackPop(StackOper); //运算符出栈
b=SeqStackPop(StackData);//两个操作数出栈
a=SeqStackPop(StackData);
t=Calc(a,oper,b);
SeqStackPush(StackData,t);//将运算结果入栈
break;
}
}else if(c>='0'&&c<='9') //若输入字符在0~9之间
{
c-='0';
q=q*10+c;
c=exp[i++];
flag=1;
}
else
{
printf("输入错误!\n");
getch();
exit(0);
}
x=SeqStackPeek(StackOper);//获取栈顶的运算符
}
q=SeqStackPop(StackData);
SeqStackFree(StackOper); //释放栈所占用的空间
SeqStackFree(StackData);
return q; //出栈,返回结果
}
主函数只需提示用户输入一个表达式字符串,然后调用CalExp函数即可。
int main()
{
int c;
char exp[80];
printf("请输入要计算的表达式(以=结束):");
scanf("%s",exp);
printf("%s%d\n",exp,CalcExp(exp));
getch();
return 0;
}
- 测试结果