今天早上和下午完成对昨天栈与树学习的巩固,复习了二叉搜索树的查找、插入、删除,重新回顾了堆的概念,复习了堆的插入、删除、建立和堆的应用——堆排序,在昨天学习了栈之后,尤其是在尝试利用栈去实现三种遍历方式的时候,就特别想看看栈的具体应用,又隐隐约约记得四则运算的实现与栈有所关联,所以今天想通过对四则运算的实现来加深自己对栈的理解。
简单四则运算的基本思路:
1.将输入的中缀表达式转化为后缀表达式;
2.对后缀表达式进行求解;
步骤一——中缀表达式转后缀表达式:
1.先将原表达式符号按顺序取出:
a.数字:传递给后缀表达式;
b.操作符:①栈为空或符号优先级大于栈顶操作符,入栈;
②优先级不大于栈顶操作符,将栈顶元素出栈直到当前符号优先级大于栈顶。
c.括号:①若为“(”,直接入栈;
②若为“)”,将栈顶元素依次出栈传递给后缀表达式,直到栈顶元素为“(”,再将“(”出栈。
2.将栈中剩余操作符依次传递给后缀表达式。
void SourceToDest(char *s,char *d,stack<char> stk){
//若为空,标记不合法,返回
if(!s){
flag=1;
return ;
}
int len=strlen(s);
char c;
int i,k;
for(i=0,k=0;i<len;i++){
c=s[i];
//若为数字,加入后缀表达式中
if(c>='0' && c<='9'){
d[k++]=c;
continue;
}
//若栈为空,压栈
if(stk.empty()){
stk.push(c);
}
//若为"(",入栈
else if(c=='('){
stk.push(c);
}
//若为")",将所有括号内符号出栈
else if(c==')'){
while(!stk.empty() && stk.top()!='('){
d[k++]=stk.top();
stk.pop();
}
stk.pop();
}
//若为"*"或"/",则将比其优先度高的(即在他前面的)"*"和"/"出栈,再将它入栈
else if(c=='*' || c=='/'){
while(!stk.empty() && (stk.top()=='*' || stk.top()=='/')){
d[k++]=stk.top();
stk.pop();
}
stk.push(c);
}
//若为"+"或"-",则将除了"("以外的(均比它优先级高) 出栈
else if(c=='+' || c=='-'){
while(!stk.empty() && stk.top()!='('){
d[k++]=stk.top();
stk.pop();
}
stk.push(c);
}
//不合法字符
else{
flag=1;
return;
}
}
//若栈不为空,弹出剩余符号
while(!stk.empty()){
d[k++]=stk.top();
stk.pop();
}
d[k]='\0';//末尾补结束符
}
步骤二——后缀表达式计算结果
1.将后缀表达式符号依次取出并重复进行如下操作直到后缀表达式被遍历:
a.数字:直接入栈;
b.操作符:从栈中依次取出两个数字a,b,根据操作符对a,b进行操作,并将得到的结果入栈。例如取出a=1,b=2,操作符为‘-’,则push(b-a),注意a,b的顺序;
2.取出栈中剩余的唯一元素为最终结果。
void Compute(char *d,stack<int> stk){
//若为空,则不合法
if(!d){
flag=1;
return ;
}
int len=strlen(d);
int i,result,a,b;
char c;
for(i=0;i<len;i++){
c=d[i];
//若为数字,压栈
if(c>='0' && c<='9'){
stk.push(c-'0');
}else{
//若为空,不合法
if(stk.empty()){
flag=1;
return ;
}
b=stk.top(); //取出操作数的第二个
stk.pop();
//若取了一个操作数就为空,不合法
if(stk.empty()){
flag=1;
return ;
}
a=stk.top(); //取出第一个操作数
stk.pop();
//根据符号进行运算
switch(c){
case '+':result=a+b;break;
case '-':result=a-b;break;
case '*':result=a*b;break;
case '/':result=a/b;break;
}
stk.push(result);//将结果压栈,参与下一次操作
}
}
result=stk.top(); //最终结果出栈
stk.pop();
cout<<result<<endl;//输出结果
}
完整代码如下(为了说明算法,此代码仅仅限制操作数为0-9之间,若要操作更大的数需进行的修改):
#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
#define N 100
int flag; //判断字符合法性
void SourceToDest(char *s,char *d,stack<char> stk);//将中缀表达式转化为后缀表达式
void Compute(char *d,stack<int> stk); //计算后缀表达式
int main()
{
char sourcelist[N],destlist[N]; //源字符串(中缀表达式),目的字符串(后缀表达式)
stack<char>opstk; //操作符栈,
stack<int>resultstk; //结果栈
cin>>sourcelist; //仅限十以内的数字
SourceToDest(sourcelist,destlist,opstk);
//cout<<destlist<<endl; 调试查看后缀表达式
if(!flag) Compute(destlist,resultstk);
return 0;
}
void SourceToDest(char *s,char *d,stack<char> stk){
//若为空,标记不合法,返回
if(!s){
flag=1;
return ;
}
int len=strlen(s);
char c;
int i,k;
for(i=0,k=0;i<len;i++){
c=s[i];
//若为数字,加入后缀表达式中
if(c>='0' && c<='9'){
d[k++]=c;
continue;
}
//若栈为空,压栈
if(stk.empty()){
stk.push(c);
}
//若为"(",入栈
else if(c=='('){
stk.push(c);
}
//若为")",将所有括号内符号出栈
else if(c==')'){
while(!stk.empty() && stk.top()!='('){
d[k++]=stk.top();
stk.pop();
}
stk.pop();
}
//若为"*"或"/",则将比其优先度高的(即在他前面的)"*"和"/"出栈,再将它入栈
else if(c=='*' || c=='/'){
while(!stk.empty() && (stk.top()=='*' || stk.top()=='/')){
d[k++]=stk.top();
stk.pop();
}
stk.push(c);
}
//若为"+"或"-",则将除了"("以外的(均比它优先级高) 出栈
else if(c=='+' || c=='-'){
while(!stk.empty() && stk.top()!='('){
d[k++]=stk.top();
stk.pop();
}
stk.push(c);
}
//不合法字符
else{
flag=1;
return;
}
}
//若栈不为空,弹出剩余符号
while(!stk.empty()){
d[k++]=stk.top();
stk.pop();
}
d[k]='\0';//末尾补结束符
}
void Compute(char *d,stack<int> stk){
//若为空,则不合法
if(!d){
flag=1;
return ;
}
int len=strlen(d);
int i,result,a,b;
char c;
for(i=0;i<len;i++){
c=d[i];
//若为数字,压栈
if(c>='0' && c<='9'){
stk.push(c-'0');
}else{
//若为空,不合法
if(stk.empty()){
flag=1;
return ;
}
b=stk.top(); //取出操作数的第二个
stk.pop();
//若取了一个操作数就为空,不合法
if(stk.empty()){
flag=1;
return ;
}
a=stk.top(); //取出第一个操作数
stk.pop();
//根据符号进行运算
switch(c){
case '+':result=a+b;break;
case '-':result=a-b;break;
case '*':result=a*b;break;
case '/':result=a/b;break;
}
stk.push(result);//将结果压栈,参与下一次操作
}
}
result=stk.top(); //最终结果出栈
stk.pop();
cout<<result<<endl;//输出结果
}