栈的应用实例4—表达式求值
- 这里用栈的特殊结构实现了算术的四则运算:先乘除后加减,从左算到右。输入格式举例:#4+2*3-10/5#(#为句子的开始或结束符号)。这里我偷了个懒,并没有实现改变优先级的 “(” 和 “)” ,原理一样。
- 首先定义了两个栈,一个为运算符栈,一个为操作数栈。思路简单来说即为:
①.构造一个算符优先关系表,开始符号进栈,第一个操作数进栈。
②.当运算符进栈的时候,与算符栈的栈顶符号比较优先级,若优先级大于它则将运算符进栈,下一个操作数进栈,重复②;若当前运算符的优先级不大于算符栈的栈顶运算符,则它暂时不进栈,执行③。
③.将算符栈的栈顶运算符与操作数栈的栈顶及次栈顶元素进行计算,使它们都出栈,把计算结果进操作数栈,重复③直到②满足;若算符栈的栈顶运算符为 “#” 结束符号,则计算完成,清空两个栈,打印计算结果。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
#define STACK_INIT_SIZE 100 //栈的初始化容量
#define STACK_INC_SIZE 10 //栈的分配增量
typedef int elemType;
//栈的数据结构
typedef struct{
elemType* base; //栈底指针
elemType* top; //栈顶指针
int stackSize; //当前已分配的栈总存储空间
}SqStack;
void initStack(SqStack& S); //构造空栈并初始化
void pushStack(SqStack& S,elemType data); //数据元素进栈
void popStack(SqStack& S); //数据元素出栈
void initStack(SqStack& S)
{
S.base=(elemType*)malloc(STACK_INIT_SIZE * sizeof(elemType));
if(!S.base) exit(1);
S.top=S.base;
S.stackSize=STACK_INIT_SIZE;
}
void pushStack(SqStack& S,elemType data)
{
if(S.top-S.base>=S.stackSize) //栈满,扩充容量
{
S.base=(elemType*)realloc(S.base,(S.stackSize+STACK_INC_SIZE) * sizeof(elemType));
if(!S.base) exit(1);
S.top=S.base+S.stackSize; //栈顶改变
S.stackSize+=STACK_INC_SIZE;
}
*S.top=data;
S.top++;
}
void popStack(SqStack& S)
{
if(S.top!=S.base)
{
S.top--;
}
}
void printStack(SqStack& S)
{
cout<<"栈中的内容为:";
for(elemType* i=S.base;i<S.top;i++)
{
int j=0;
cout<<*(i+j)<<" ";
j++;
}
cout<<endl;
}
//(i,j)对应的值表示下一个运算符与栈顶运算符的逻辑关系
//+ - * / ( ) # :0为不存在,1为小于,2为大于,3为等于
int opfirst[7][7]={
{ 1, 1, 1, 1, 1, 2, 2 }, // +:43
{ 1, 1, 1, 1, 1, 2, 2 }, // -:45
{ 2, 2, 1, 1, 1, 2, 2 }, // *:42
{ 2, 2, 1, 1, 1, 2, 2 }, // /:47
{ 1, 1, 1, 1, 1, 3, 0 }, // (:40
{ 2, 2, 2, 2, 0, 2, 2 }, // ):41
{ 1, 1, 1, 1, 1, 0, 3 } // #:35
};
int mid=0;
void calFunction(SqStack& SF,SqStack& SS,char c)
{
int i,j;
//通过switch获得到i和j,在数组中查询两个运算符之间的优先级
switch(c)
{
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(*(SF.top-1))
{
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;
}
if(opfirst[i][j]==2) //若下一个运算符优先级大于栈顶运算符,则进栈
{
pushStack(SF,c);
cin>>i;
pushStack(SS,i); //后一个算数进栈
cin>>c;
if(c!='#') //c不为结束符则继续调用该函数
{
calFunction(SF,SS,c);
}
else //否则计算中间结果,SF栈顶运算符出栈,SF栈顶操作数出栈,SF栈顶操作数出栈
{
for(;;)
{
switch(*(SF.top-1))
{
case '+': mid=(*(SS.top-2))+(*(SS.top-1)); break;
case '-': mid=(*(SS.top-2))-(*(SS.top-1)); break;
case '*': mid=(*(SS.top-2))*(*(SS.top-1)); break;
case '/': mid=(*(SS.top-2))/(*(SS.top-1)); break;
case '(': i=4; break;
case ')': i=5; break;
case '#': i=6; break;
}
popStack(SF);
popStack(SS);
popStack(SS);
pushStack(SS,mid);
if(*(SF.top-1)=='#') //直到结束,清空栈,输出计算结果
{
popStack(SF);
popStack(SS);
cout<<"计算结果为:"<<mid<<endl;
exit(0);
}
}
}
}
//若下一个运算符优先级小于栈顶运算符,则暂时不进栈,计算中间结果,直到下一个运算符优先级大于栈顶运算符
else if(opfirst[i][j]==1||opfirst[i][j]==3)
{
switch(*(SF.top-1))
{
case '+': mid=(*(SS.top-2))+(*(SS.top-1)); break;
case '-': mid=(*(SS.top-2))-(*(SS.top-1)); break;
case '*': mid=(*(SS.top-2))*(*(SS.top-1)); break;
case '/': mid=(*(SS.top-2))/(*(SS.top-1)); break;
case '(': i=4; break;
case ')': i=5; break;
case '#': i=6; break;
}
popStack(SF);
popStack(SS);
popStack(SS);
pushStack(SS,mid);
calFunction(SF,SS,c);
}
}
int main()
{
//表达式求值: + - * /
SqStack SS,SF; //定义算数栈SS,算符栈SF
initStack(SS);
initStack(SF);
char c;
int i;
cin>>c;
pushStack(SF,c); //运算符进栈 #:40进栈
cin>>i;
pushStack(SS,i); //前一个算数进栈
cin>>c;
calFunction(SF,SS,c);
return 0;
}
运行结果: