本博文源于严蔚敏老师的《数据结构》,今天就来聊聊如何实现一位数运算数加法和多位数运算符加法。本代码完全对书中的代码再现,没有其他的过多的想法,包括多位数运算法加法也只是对原有内容基础上修改罢了。如果读者对此非常感兴趣,也可以收藏进行深度学习一波。
1、原题再现
实现表达式求值
2、测试效果
3、题目分析
实现表达式求值是栈的应用,一般方法如下,用两个栈,一个运算符栈,一个是操作数栈,读入字符,遇见操作数比较栈顶运算符看是否入栈,还是弹出操作数进行操作,如果遇见操作数那就入栈,具体的流程如下:
为实现运算符优先算法,可以使用两个工作栈
OPTR栈:存储运算符栈
OPND:存储操作数或运算结果
In函数:判定读入的字符ch是否为运算符
Precede 是判定运算符栈的栈顶元素与读入的元素负之间优先关系的函数
Operate:为进行二元运算
步骤如下:
1、初始化OPTR栈和OPND栈,将表达式起始负“#”压入OPTR栈
2、扫描表达式,读入第一个字符ch,如果表达式没有扫描完毕至"#"或OPTR的栈顶元素不为 “#”则循环执行以下操作
2.1若ch不是运算符则压入OPND栈,读入下一个字符ch
2.2若ch是运算符,则根据OPTR的栈顶元素和ch的优先级比较结果,做不同的处理
2.3若是小于,则ch压入optr栈,读入下一个字符ch
2.4若是大于,则弹出optr栈顶的运算符,从OPND栈弹出两个数,进行相应运算,借故偶压入OPND栈,
2.5若是等于,则optr的栈顶元素是“(”且ch是”)“这时弹出OPTR栈顶的”(“相当于括号匹配成功,然后读入下一个字符1ch
3.opnd栈顶元素即为表达式求值结果,返回此元素
核心代码
核心代码就是对这核心步骤进行实现
int main(){
stack<int> OPND;//运算数栈
stack<char> OPTR;//运算操符栈
OPTR.push('#');//表达式起始”#“压入OPTR栈
char ch;
char theta;
int a,b,num=0;
cin >> ch;
while(ch != '#' || OPTR.top()!='#'){ //表达式没有扫描完毕或OPTR的栈顶元素不为“#”
if(!In(ch)){ //ch不是运算符则进OPND栈
num=num*10+(ch-'0');
cin >> ch;
if(In(ch)) {
OPND.push(num);
num =0;
}
}else{
switch (Precede(OPTR.top(),ch)){//比较OPTR的栈顶元素和ch的优先级
case '<':
OPTR.push(ch);//当前字符ch压入optr栈,读入下一个字符ch
cin >> ch;
break;
case '>':
theta = OPTR.top();OPTR.pop();//弹出OPTR栈顶元素符
b = OPND.top();OPND.pop();//弹出OPND栈顶的两个运算符
a= OPND.top();OPND.pop();
OPND.push(Operate(a,theta,b));//将运算结果压入OPND栈
break;
case '=':
OPTR.pop(); //OPTR的栈顶元素是"("且ch是")"
cin >> ch; //弹出OPTR栈顶的"(",读入下一字符ch
break;
default:
exit(ERROR);
}
}
}
cout << OPND.top();//求值结果
return 0;
}
完整代码
#include<iostream>
#include<stack>
#define ERROR -1
using namespace std;
//为实现运算符优先算法,可以使用两个工作栈
//一个OPTR:寄存运算符
//OPND:寄存操作数或运算结果
//In:判定读入的字符ch是否为运算符
//Precede 是判定运算符栈的栈顶元素与读入的元素负之间优先关系的函数
//Operate:为进行二元运算
bool In(char ch){
if(ch == '+' || ch=='-' || ch=='*' || ch=='/' || ch=='(' || ch==')' || ch=='#'){
return true;
}
return false;
}
char Precede(char ch1,char ch2){
if(ch1 =='+' || ch1 == '-'){
if(ch2 == '*' || ch2=='/' || ch2=='('){
return '<';
}else{
return '>';
}
}else if(ch1 == '*' || ch1=='/'){
if(ch2 == '('){
return '<';
}else {
return '>';
}
}else if(ch1 == '('){
if(ch2==')'){
return '=';
}else if(ch2 == '#'){
return 'E';
}else{
return '<';
}
}else if(ch1 == ')'){
if(ch2=='('){
return 'E';
}else{
return '>';
}
}else if(ch1 =='#'){
if(ch2=='#'){
return '=';
}else if(ch2 == ')'){
return 'E';
}else{
return '<';
}
}
return 'E';
}
int Operate(int a,char theta,int b){
if(theta == '+' )
return a+b;
else if(theta == '-')
return a-b;
else if(theta == '*')
return a*b;
else if(theta == '/')
return a/b;
else
return 0;
}
int main(){
//①初始化OPTR栈和OPND栈,将表达式起始负“#”压入OPTR栈
//②扫描表达式,读入第一个字符ch,如果表达式没有扫描完毕至"#"或OPTR的栈顶元素不为
// “#”则循环执行以下操作
//若ch不是运算符则压入OPND栈,读入下一个字符ch
//若ch是运算符,则根据OPTR的栈顶元素和ch的优先级比较结果,做不同的处理
//若是小于,则ch压入optr栈,读入下一个字符ch
//若是大于,则弹出optr栈顶的运算符,从OPND栈弹出两个数,进行相应运算,借故偶压入OPND栈,
//若是等于,则optr的栈顶元素是“(”且ch是”)“这时弹出OPTR栈顶的”(“相当于括号匹配成功,然后读入下一个字符1ch
//③ opnd栈顶元素即为表达式求值结果,返回此元素
stack<int> OPND;//运算数栈
stack<char> OPTR;//运算操符栈
OPTR.push('#');//表达式起始”#“压入OPTR栈
char ch;
char theta;
int a,b,num=0;
cin >> ch;
while(ch != '#' || OPTR.top()!='#'){ //表达式没有扫描完毕或OPTR的栈顶元素不为“#”
if(!In(ch)){ //ch不是运算符则进OPND栈
num=num*10+(ch-'0');
cin >> ch;
if(In(ch)) {
OPND.push(num);
num =0;
}
}else{
switch (Precede(OPTR.top(),ch)){//比较OPTR的栈顶元素和ch的优先级
case '<':
OPTR.push(ch);//当前字符ch压入optr栈,读入下一个字符ch
cin >> ch;
break;
case '>':
theta = OPTR.top();OPTR.pop();//弹出OPTR栈顶元素符
b = OPND.top();OPND.pop();//弹出OPND栈顶的两个运算符
a= OPND.top();OPND.pop();
OPND.push(Operate(a,theta,b));//将运算结果压入OPND栈
break;
case '=':
OPTR.pop(); //OPTR的栈顶元素是"("且ch是")"
cin >> ch; //弹出OPTR栈顶的"(",读入下一字符ch
break;
default:
exit(ERROR);
}
}
}
cout << OPND.top();//求值结果
return 0;
}