百度百科---逆波兰式

引自:http://baike.baidu.com/view/2582.htm

 

定义 

 逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)

  如:我们平时写a+b,这是中缀表达式,写成后缀表达式就是:ab+

  (a+b)*c-(a+b)/e的后缀表达式为:

  (a+b)*c-(a+b)/e

  →((a+b)*c)((a+b)/e)-

  →((a+b)c*)((a+b)e/)-

  →(ab+c*)(ab+e/)-

  →ab+c*ab+e/-

 

算法实现  

    将一个普通的中序表达式转换为逆波兰表达式的一般算法是:

  (1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。

  (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。

  (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。

  (4)如果不是数字,该字符则是运算符,此时需比较优先关系。

  做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。

  (5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

逆波兰式的作用

  对于实现逆波兰式算法,难度并不大,但为什么要将看似简单的中序表达式转换为复杂的逆波兰式?原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中序表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。

  下面以(a+b)*c为例子进行说明:

  (a+b)*c的逆波兰式为ab+c*,假设计算机把ab+c*按从左到右的顺序压入栈中,并且按照遇到运算符就把栈顶两个元素出栈,执行运算,得到的结果再入栈的原则来进行处理,那么ab+c*的执行结果如下:

  1)a入栈(0位置)

  2)b入栈(1位置)

  3)遇到运算符“+”,将a和b出栈,执行a+b的操作,得到结果d=a+b,再将d入栈(0位置)

  4)c入栈(1位置)

  5)遇到运算符“*”,将d和c出栈,执行d*c的操作,得到结果e,再将e入栈(0位置)

  经过以上运算,计算机就可以得到(a+b)*c的运算结果e了。

  逆波兰式除了可以实现上述类型的运算,它还可以派生出许多新的算法,数据结构,这就需要灵活运用了。逆波兰式只是一种序列体现形式。

程序实现 

 //逆波兰式 (C语言版)

  #include<iostream.h>

  #include<stdlib.h>

  #include<stdio.h>

  #include<math.h>

  #define max 100

  char ex[max]; /*存储后缀表达式*/

  void trans(){ /*将算术表达式转化为后缀表达式*/

  char str[max]; /*存储原算术表达式*/

  char stack[max]; /*作为栈使用*/

  char ch;

  int sum,i,j,t,top=0;

  printf("*****************************************/n");

  printf("*输入一个求值的表达式,以#结束。*/n");

  printf("******************************************/n");

  printf("算数表达式:");

  i=0; /*获取用户输入的表达式*/

  do{

  i++;

  cin>>str[i];/*此步我用的是C++ C语言的话在后面 之所以用这个有一点区别 都*/

  //scanf("%c",&str[i]);

  }while(str[i]!='#' && i!=max);

  sum=i;

  t=1;i=1;

  ch=str[i];i++;

  //

  while(ch!='#'){

  switch(ch){

  case '(': /*判定为左括号*/

  top++;stack[top]=ch;

  break;

  case ')': /*判定为右括号*/

  while(stack[top]!='('){

  ex[t]=stack[top];top--;t++;

  }

  top--;

  break;

  case '+': /*判定为加减号*/

  case '-':

  while(top!=0&&stack[top]!='('){

  ex[t]=stack[top];top--;t++;

  }

  top++;stack[top]=ch;

  break;

  case '*': /*判定为乘除号*/

  case '/':

  while(stack[top]=='*'||stack[top]=='/'){

  ex[t]=stack[top];top--;t++;

  }

  top++;stack[top]=ch;

  break;

  case ' ':break;

  default:while(ch>='0'&&ch<='9'){ /*判定为数字*/

  ex[t]=ch;t++;

  ch=str[i];i++;

  }

  i--;

  ex[t]=' ';t++;

  }

  ch=str[i];i++;

  }

  while(top!=0){

  ex[t]=stack[top];t++;top--;

  }

  ex[t]=' ';

  printf("/n/t原来表达式:");

  for(j=1;j<sum;j++)

  printf("%c",str[j]);

  printf("/n/t逆波兰式:",ex);

  for(j=1;j<t;j++)

  printf("%c",ex[j]);

  }

  void compvalue(){ /*计算后缀表达式的值*/

  float stack[max],d; /*作为栈使用*/

  char ch;

  int t=1,top=0; /*t为ex下标,top为stack下标*/

  ch=ex[t];t++;

  while(ch!=' '){

  switch(ch){

  case '+':

  stack[top-1]=stack[top-1]+stack[top];

  top--;

  break;

  case '-':

  stack[top-1]=stack[top-1]-stack[top];

  top--;

  break;

  case '*':

  stack[top-1]=stack[top-1]*stack[top];

  top--;

  break; case '/':

  if(stack[top]!=0) stack[top-1]=stack[top-1]/stack[top];

  else{

  printf("/n/t除零错误!/n");

  exit(0); /*异常退出*/

  }

  top--;

  break;

  default:

  d=0;

  while(ch>='0'&&ch<='9'){

  d=10*d+ch-'0'; /*将数字字符转化为对应的数值*/

  ch=ex[t];t++;

  }

  top++;

  stack[top]=d;

  }

  ch=ex[t];t++;

  }

  printf("/n/t计算结果:%g/n",stack[top]);

  }void main(){

  trans();

  compvalue();

  }

  数据结构版

  int precede(char op)

  { int x;

  switch(op)

  {

  case '*': x=2; break;

  case '/': x=2; break;

  case '+': x=1; break;

  case '-': x=1; break;

  default : x=0;

  }

  return x;

  }

  char *RPExpression(char *e)

  {/* 返回表达式e的逆波兰式 */

  char *c;

  c=(char*)malloc(sizeof(char)*20); //不能用char c[]

  Stack s1;

  InitStack(s1);

  int i=0,j=0;

  char ch;

  Push(s1,'@');

  ch=e[i++];

  while(ch!= 0)

  {

  if(ch=='(')

  {

  Push(s1,ch);

  ch=e[i++];

  }

  else if(ch==')')

  {

  while(Top(s1)!='(')

  {

  Pop(s1,c[j++]);

  }

  /* to[j++]=pop(&s1);*/

  Pop(s1,ch);

  ch=e[i++];

  }

  else if(ch=='+'||ch=='-'||ch=='*'||ch=='/')

  {

  char w;

  w=Top(s1);

  while(precede(w)>=precede(ch))

  {

  Pop(s1,c[j++]);

  w=Top(s1);

  }

  Push(s1,ch);

  ch=e[i++];

  }

  else

  {

  //while((ch<='z'&&ch>='a')||(ch<='Z' && ch>='A')){

  c[j++]=ch;

  ch=e[i++];

  //}

  //c[j++]=' ';

  }

  }

  Pop(s1,ch);

  while(ch!='@')

  {

  c[j++]=ch;

  Pop(s1,ch);

  }

  //c[j++]=;

  c[j++]=0;

  return c;

  }

  还有一种方法,用2叉树.

 

二叉树法  

     将最终进行的预算符记为根节点,将两边的表达式分别记为左右子树,一次进行直到所有的运算符与数字或字母标在一棵二叉树上。然后对二叉树进行后续遍历,记下遍历的顺序即可。

 

扩展阅读:

1.http://fengke82.spaces.live.com/blog/cns!77368940f698f604!137.entry

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值