转换逆波兰式(栈的应用)

栈的应用:表达式求值

学完栈后,就可以利用栈来计算表达式了:
我们输入的是中缀表达式,首先我们要把它转换成逆波兰式(后缀表达式):
思想:
从左到右依次扫描中缀表达式:
1.是操作数,直接输出
2.是’(’,入栈
3.是’)’,取出栈顶元素放入逆波兰式,直到栈顶元素为’('时为止
4.是操作符,与栈顶元素比较(高于栈顶元素优先级,入栈;低于栈顶元素优先级,取出栈顶元素放入逆波兰式,弹出栈顶元素,直到栈顶元素优先级低于当前操作符的优先级)。
涉及到的操作符优先级关系:* = / > + = - > ( = )

以下有关栈的部分函数我不会过多说明,这篇文章我着重写下中缀表达式转换成逆波兰式后求值,不过文末会有所有的源代码。
中缀表达式转换为逆波兰式:

int check(char ch)//确定优先级关系的函数
{
 switch(ch)
 {
 case '+':
 case '-':
  return 0;
 case '*':
 case '/':
  return 1;
 }
 return -1;
}

//我想的是用double数组来存放逆波兰式,方便最后的计算
void infix(char* infixexp)
{
 int len;
 len=strlen(infixexp);
 linkstack stack=set();//创建一个空栈
 for(int i=0;i<len;i++)
 {
  bool p=0;//为了判断执行了while循环
   while(infixexp[i]>='0' && infixexp[i]<='9')
  {
   p=1;
   postexp[k]=postexp[k]*10+(infixexp[i]-'0');//将前缀表达式里的数字字符变为真正的数字并添加到逆波兰式
   i++;//进入下一个字符(一个数字可以由多个数字字符组成)
   if(i>=len)
    break;
  }
  if(p==1)
  {
   k++;
  }
  if(infixexp[i]=='(')
  {
   push_link(stack,infixexp[i]);//入栈
  }
  if(infixexp[i]==')')
  {
   while(is_link(stack)==false && top_link(stack)!='(')//上面思想有说明
   {
    switch(top_link(stack))//取栈顶元素
    {
    case '+':postexp[k]=-1;break;
    case '-':postexp[k]=-2;break;
    case '*':postexp[k]=-3;break;
    case '/':postexp[k]=-4;break;
    default:break;//加减乘除分别用以上数字来代替
    }
    k++;
    pop_link(stack);//出栈
   }
   pop_link(stack);
  }
  if(infixexp[i]=='+' || infixexp[i]=='-' || infixexp[i]=='*' || infixexp[i]=='/')
  {
   while(is_link(stack)==false && check(infixexp[i])<=check(top_link(stack)))//判断栈是否为空及操作符优先级关系
   {
    switch(top_link(stack))
    {
    case '+':postexp[k]=-1;break;
    case '-':postexp[k]=-2;break;
    case '*':postexp[k]=-3;break;
    case '/':postexp[k]=-4;break;
    default:break;
    }
    pop_link(stack);
    k++;
   }
   push_link(stack,infixexp[i]);
  }
 }
 //把栈中元素全部出栈添加到逆波兰式中
 while(is_link(stack)==false)
 {
  switch(top_link(stack))
  {
  case '+':postexp[k]=-1;break;
  case '-':postexp[k]=-2;break;
  case '*':postexp[k]=-3;break;
  case '/':postexp[k]=-4;break;
  default:break;
  }
  pop_link(stack);
  k++;
 }
 for(int i=0;i<k;i++)//输出逆波兰式
  cout<<postexp[i]<<" ";
}

上面完成了前缀表达式转换成逆波兰式,下面就要实现逆波兰式求值的算法:
算法思路如下:
顺序扫描逆波兰式:
1.是操作数,入栈
2.是操作符,取出栈中两个操作数进行计算,再把结果入栈;
3.扫描结束后,栈顶元素就是前缀表达式的结果值。
逆波兰式求值的算法:

double evaluate(double exp[])//double数组可以准确地存储两数相除的结果
{
 linkstack2 stack=set2();//这里用到另一个栈的创建,文章下面会有说明
 for(int i=0;i<k;i++)
 {
  if(exp[i]>0)//大于0表示是操作数,因为操作符都是负数
  {
   push_link2(stack,exp[i]);//另一个入栈
  }
  else
  {
   double val1=top_link2(stack);//另一个取栈顶元素
   pop_link2(stack);//另一个出栈
   double val2=top_link2(stack);
   pop_link2(stack);
   if(exp[i]==-1)
    push_link2(stack,val1+val2);
   if(exp[i]==-2)
    push_link2(stack,val2-val1);
   if(exp[i]==-3)
    push_link2(stack,val1*val2);
   if(exp[i]==-4)
    push_link2(stack,val2/val1);//减法和除法两数的位置要搞清楚
  }
 }
 return top_link2(stack);
}

以上就是本篇文章的重要的两个算法!(考虑到有的博主对栈的理解还不是很深刻,我就把原代码也讲解一下)

AC代码如下:

#include <iostream>
using namespace std;
double postexp[100]={0};
int k=0;//postexp[]和k都定义的全局变量

typedef struct Node
{
 char data;
 struct Node* next;
}*pnode,*top,*linkstack;//结点类型、栈顶、链栈类型

linkstack set()//创建空链栈
{
 linkstack top=(linkstack)malloc(sizeof(Node));
 if(top!=NULL)
  top->next=NULL;
 else
  cout<<"创建失败!"<<endl;
 return top;
}

bool is_link(linkstack top)//判断一个链栈是否为空
{
 if(top->next==NULL)
  return true;
 return false;
}

void push_link(linkstack top,char x)//进栈
{
 pnode p;
 p=(pnode)malloc(sizeof(Node));//申请结点空间
 if(p==NULL)
  return;
 p->data=x;//数据域赋值
 p->next=top->next;//指针域赋值
 top->next=p;//改变栈顶
}

char top_link(linkstack top)
{
 if(is_link(top)==true)//用上面函数判断是否为空链栈
 {
  cout<<"栈已空"<<endl;
  return 'f';
 }
 else
  return top->next->data;//取栈顶元素
}

void pop_link(linkstack top)//删除栈顶元素
{
 pnode p;
 if(is_link(top)==true)
 {
  cout<<"栈已空"<<endl;
  return;
 }
 p=top->next;//p指向栈顶元素
 top->next=p->next;//改变栈顶指针
 free(p);//释放删除结点空间
}

//第二个栈类似第一个栈,只是数据类型改变,其他函数思想基本一致
typedef struct Node2//命名没有那么规范,还请理解
{
 double data2;
 struct Node2* next2;
}*pnode2,*top2,*linkstack2;

linkstack2 set2()
{
 linkstack2 top2=(linkstack2)malloc(sizeof(Node2));
 if(top2!=NULL)
  top2->next2=NULL;
 else
  cout<<"创建失败!"<<endl;
 return top2;
}

bool is_link2(linkstack2 top)
{
 if(top->next2==NULL)
  return true;
 return false;
}

void push_link2(linkstack2 top2,double x)
{
 pnode2 ps;
 ps=(pnode2)malloc(sizeof(Node2));
 if(ps==NULL)
  return;
 ps->data2=x;
 ps->next2=top2->next2;
 top2->next2=ps;
}

double top_link2(linkstack2 top)
{
 if(is_link2(top)==1)
 {
  cout<<"栈已空"<<endl;
  return 0;
 }
 else
  return top->next2->data2;
}

void pop_link2(linkstack2 top)
{
 pnode2 p;
 if(is_link2(top)==1)
 {
  cout<<"栈已空"<<endl;
  return;
 }
 p=top->next2;
 top->next2=p->next2;
 free(p);
}

int check(char ch)
{
 switch(ch)
 {
 case '+':
 case '-':
  return 0;
 case '*':
 case '/':
  return 1;
 }
 return -1;
}

void infix(char* infixexp)
{
 int len;
 len=strlen(infixexp);
 linkstack stack=set();
 for(int i=0;i<len;i++)
 {
  bool p=0;
  while(infixexp[i]>='0' && infixexp[i]<='9')
  {
   p=1;
   postexp[k]=postexp[k]*10+(infixexp[i]-'0');
   i++;
   if(i>=len)
    break;
  }
  if(p==1)
  {
   k++;
  }
  if(infixexp[i]=='(')
  {
   push_link(stack,infixexp[i]);
  }
  if(infixexp[i]==')')
  {
   while(is_link(stack)==false && top_link(stack)!='(')
   {
    switch(top_link(stack))
    {
    case '+':postexp[k]=-1;break;
    case '-':postexp[k]=-2;break;
    case '*':postexp[k]=-3;break;
    case '/':postexp[k]=-4;break;
    default:break;
    }
    k++;
    pop_link(stack);
   }
   pop_link(stack);
  }
  if(infixexp[i]=='+' || infixexp[i]=='-' || infixexp[i]=='*' || infixexp[i]=='/')
  {
   while(is_link(stack)==false && check(infixexp[i])<=check(top_link(stack)))
   {
    switch(top_link(stack))
    {
    case '+':postexp[k]=-1;break;
    case '-':postexp[k]=-2;break;
    case '*':postexp[k]=-3;break;
    case '/':postexp[k]=-4;break;
    default:break;
    }
    pop_link(stack);
    k++;
   }
   push_link(stack,infixexp[i]);
  }
 }
 while(is_link(stack)==false)
 {
  switch(top_link(stack))
  {
  case '+':postexp[k]=-1;break;
  case '-':postexp[k]=-2;break;
  case '*':postexp[k]=-3;break;
  case '/':postexp[k]=-4;break;
  default:break;
  }
  pop_link(stack);
  k++;
 }
 for(int i=0;i<k;i++)
  cout<<postexp[i]<<" ";
}

double evaluate(double exp[])
{
 linkstack2 stack=set2();
 for(int i=0;i<k;i++)
 {
  if(exp[i]>0)
  {
   push_link2(stack,exp[i]);
  }
  else
  {
   double val1=top_link2(stack);
   pop_link2(stack);
   double val2=top_link2(stack);
   pop_link2(stack);
   if(exp[i]==-1)
    push_link2(stack,val1+val2);
   if(exp[i]==-2)
    push_link2(stack,val2-val1);
   if(exp[i]==-3)
    push_link2(stack,val1*val2);
   if(exp[i]==-4)
    push_link2(stack,val2/val1);
  }
 }
 return top_link2(stack);
}

int main()
{
 char* p;
 p=(char*)malloc(sizeof(char)*100);
 cout<<"输入要计算的表达式:"<<endl;
 cin>>p;
 cout<<"输出后缀表达式(-1为'+' -2为'-' -3为'*' -4为'/'):"<<endl;
 infix(p);
 cout<<endl<<"输出计算最终的结果(出现栈已空时,说明当前运算符多于数字,不用担心):"<<endl;
 cout<<evaluate(postexp)<<endl;
 return 0;
}

学会了求前缀表达式的结果值后,就可以尝试着开发一个小项目来做一个简易计算器,代码中有什么改善或错误的地方,请各位大佬评论指出。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值