任何一个表达式都是操作数、运算符、界限符组成的,统称他们为单词。一般地,操作数既可以是常数,也可以是被说明为变量或常量的标识符,运算符可以被分为算数运算符、关系运算符和逻辑运算符三类,基本界限符有左右括号和表达式结束符等。为了叙述的简洁,在此仅讨论简单算数表达式的求值问题,这种表达式仅含加减乘数四种运算符。
下面把运算符和界限符统称为算符
我们知道,算数四则运算遵循下面规律:
(1)先乘除后加减
(2)从左到右
(3)先括号内,后括号外
【案例实现】
为了实现算符优先算法,可以使用两个栈,一个栈为OPTR,用于寄存运算符,一个栈为OPND,用于寄存操作数或运算结果
【算法步骤】
1.初始化OPTR和OPND两个栈,并将表达式初始符“#”压入OPTR中
2.扫描表达式,读入第一个字符ch,如果表达式没有扫描完毕至“#”或OPTR的栈顶元素不为“#”时,则循环执行以下操作:
(1)若ch不是运算符,则压入OPND中,读入下一字符
(2)若ch是运算符,则根据OPTR的栈顶元素和ch的优先级比较结果,做不同的处理:
[1]若是小于,则ch压入OPTR中,读下一字符
[2]若是大于,则弹出OPTR栈顶的运算符,从OPND栈中弹出两个数,进行响应的运算,结果压人OPND中
[3]若是等于,则OPTR的栈顶元素是"(“且ch是”)",这时弹出OPTR栈顶的“(",相当于括号匹配成功,然后读入下一字符ch
3.OPND栈顶元素即为表达式求值的结果,返回此元素
【算法分析】
【算法代码】
char EvaluateExpression()
{
//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈
InitStack(OPND); //初始化OPTR栈
InitStack(OPTR); //初始化OPND栈
push(OPTR,'#'); //将表达式起始符'#'压入栈OPTR中
cin>>ch;
while(ch!='#'&&GetTop(OPTR)!='#') //表达式没有扫描完毕或者OPTR栈顶不为“#”时
{
if(!In(ch)) //如果ch不是运算符,入栈,并扫描下一个字符
{
push(OPTR,ch);
cin>>ch;
}
else
{
switch(Precede(OPTR),ch) //比较OPTR栈顶元素和ch的优先级
{
case '<':
push(OPTR,ch);
cin>>ch;
break;
case '>':
//记住,这个地方不用cin,为什么不用具体看上面流程图
pop(OPTR,theta);
pop(OPND,b);
pop(OPND,a);
push(OPND,operate(a,theta,b));
break;
case '=':
pop(OPTR,x);
cin>>ch;
break;
}
}
}
return GetTop(OPND); //运算结果最终在OPND的栈顶
}
另外需要特别注意的是,上述算法中的操作数只能是一位数,因为这里使用的是OPND栈是字符栈,如果要进行多位数运算,则需要将OPND改为数栈,读入的数字字符平成数之后再入栈
#include<iostream>
using namespace std;
typedef struct Node
{
char data;
struct Node *next;
};
typedef struct Stack
{
struct Node *top;
int size;
};
bool InitStack(Stack *&s)
{
s->top = NULL;
s->size = 0;
if (s->top == NULL)
return true;
return false;
}
void push(Stack *&s, char ch)
{
Node *newNode = new Node;
newNode->data = ch;
newNode->nex