zoukankan      html  css  js  c++  java
  • 中缀表达式 转 (逆)波兰表达式

    由于两者方法相近,所以直接放一起方便互相对比

    方法参考相关大神的讲解,特此说明,代码为本人所写,转载请声明!

    本人测试了五组数据,结果已附图如下,暂时没发现问题,如有问题,多谢指出。

    以下摘自@wanghetao http://www.cnblogs.com/wanghetao/archive/2012/04/23/2466580.html


    一、 将中缀表达式转换成后缀表达式算法:
      1、从左至右扫描一中缀表达式。
      2、若读取的是操作数,则判断该操作数的类型,并将该操作数存入操作数堆栈
      3、若读取的是运算符
        (1) 该运算符为左括号"(",则直接存入运算符堆栈。
        (2) 该运算符为右括号")",则输出运算符堆栈中的运算符到操作数堆栈,直到遇到左括号为止。
        (3) 该运算符为非括号运算符:
          (a) 若运算符堆栈栈顶的运算符为括号(只可能是左括号),则直接存入运算符堆栈。
          (b) 若比运算符堆栈栈顶的运算符优先级高,则直接存入运算符堆栈。
          (c) 若比运算符堆栈栈顶的运算符优先级低或相等,则不断输出栈顶运算符到操作数堆栈,直到栈顶没有运算符的优先级大于或者等于当前预算符(即栈顶存在运算符的话,优先级一定是小于当前运算符),最后将当前运算符压入运算符堆栈。
      4、当表达式读取完成后运算符堆栈中尚有运算符时,则依序取出运算符到操作数堆栈,直到运算符堆栈为空。

    二、逆波兰表达式求值算法:
      1、从左到右依次扫描语法单元的项目。
      2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
      3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
      4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
      5、将运算结果重新压入堆栈。
      6、重复步骤2-5,堆栈中即为结果值。

    -------------------------------------------------分界线-------------------------------------------------

    以下摘自@unixfy http://www.cnblogs.com/unixfy/p/3344550.html

    一、 将中缀表达式转换成前缀表达式算法:
      1、首先设定一个操作符栈,从右到左顺序扫描整个中缀表达式,如果是操作数,则直接归入前缀表达式;
      2、如果是操作符,则检测器是否是右括号,如果是右括号,则直接将其入栈;
      3、如果是左括号,则将栈中的操作符依次弹栈,归入前缀表达式,直至遇到右括号,将右括号弹栈,处理结束;
      4、如果是其他操作符,则检测栈顶操作符的优先级与当前操作符的优先级关系,
      5、如果栈顶操作符优先级大于当前操作符的优先级,则弹栈,并归入前缀表达式,直至栈顶操作符优先级小于等于当前操作符优先级,这时将当前操作符压栈。
      6、当扫描完毕整个中缀表达式后,检测操作符栈是否为空,如果不为空,则依次将栈中操作符弹栈,归入前缀表达式。最后,将前缀表达式翻转,得到中缀表达式对应的前缀表达式。

    二、波兰表达式求值算法:
      1、从右到左依次扫描语法单元的项目。
      2、如果扫描的项目是操作数,则将其压入操作数堆栈,并扫描下一个项目。
      3、如果扫描的项目是一个二元运算符,则对栈的顶上两个操作数执行该运算。
      4、如果扫描的项目是一个一元运算符,则对栈的最顶上操作数执行该运算。
      5、将运算结果重新压入堆栈。
      6、重复步骤2-5,堆栈中即为结果值。

     
     

     

    中缀转前缀

    中缀转后缀

    操作符栈

    操作符栈

    扫描顺序

    从右到左

    从左到右

    遇到操作数

    直接归入

    直接归入

    遇到右括号

    直接入栈

    将栈中操作符依次弹栈,归入,直至遇到左括号,将左括号弹栈,处理完毕

    遇到左括号

    将栈中操作符依次弹栈,归入,直至遇到右括号,将右括号弹栈,处理完毕

    直接入栈

    遇到其他操作符

    检测栈顶操作符优先级与当前操作符优先级关系,如果栈顶大于当前,则出栈,归入,直至栈顶小于等于当前,并将当前操作符入栈

    检测栈顶与当前优先级关系,如果栈顶大于等于当前则出栈,归入,直至栈顶小于当前,并将当前操作符入栈

    操作符栈中的优先级

    从栈底到栈顶操作优先级:非递减。即:栈顶可以大于或等于下面的

    从栈底到栈顶优先级:递增。即:栈顶必须大于下面的

    是否翻转

    翻转

    无需翻转

    运行结果如下:

    -------------------------------------------------代码区-------------------------------------------------

      1 #include <iostream>
      2 #include<stdlib.h>
      3 
      4 using namespace std;
      5 
      6 #define STACK_INIT_SIZE 100
      7 #define STACKINCREASE 10
      8 
      9 //为了简化问题,数字和符号统一当成字符看待
     10 //由此导致的后果是接下来所有的运算过程中不允许出现小数,而且由于是利用ASCII表来储存整数,
     11 //所以每个运算数都只能取0-9的一位数,暂时没有考虑负数问题.
     12 //暂时没有考虑非法输入
     13 
     14 typedef struct
     15 {
     16     char *base;
     17     char *top;
     18     int stacksize;
     19 }SqStack;
     20 
     21 
     22 int InitStack(SqStack &S)
     23 {
     24     S.base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));
     25     if(!S.base)
     26     {
     27         cout<<"分配空间失败!";
     28         exit(-1);
     29     }
     30     S.top=S.base;
     31     S.stacksize=STACK_INIT_SIZE;
     32     return 0;
     33 }
     34 
     35 
     36 int Push(SqStack &S,char e)
     37 {
     38     if((S.top-S.base)>=STACK_INIT_SIZE)
     39     {
     40         S.base=(char *)realloc(S.base,(STACK_INIT_SIZE+STACKINCREASE)*sizeof(char));
     41         if(!S.base)
     42         {
     43            cout<<"分配空间失败!";
     44             exit(-1);
     45         }
     46         S.top=S.base+STACK_INIT_SIZE;
     47         S.stacksize=STACK_INIT_SIZE+STACKINCREASE;
     48     }
     49     *(S.top)=e;//结构体
     50     S.top++;
     51     return 0;
     52 }
     53 
     54 
     55 int Pop(SqStack &S,char &e)
     56 {
     57     if(S.base==S.top)
     58     {
     59         cout<<"栈为空!";
     60         exit(0);
     61     }
     62     S.top--;
     63     e=*(S.top);
     64     return 0;
     65 }
     66 
     67 int GetTop(SqStack &S,char &e)
     68 {
     69     if(S.base==S.top)
     70     {
     71         cout<<"栈为空!";
     72         return 0;
     73     }
     74     else
     75     {
     76         e=*(S.top-1);
     77         return 1;
     78     }
     79 }
     80 
     81 
     82 int EmptyStack(SqStack &S)
     83 {
     84     if(S.base==S.top) return 1;//stack is empty!
     85     else return 0;//stack is not empty!
     86 }
     87 
     88 
     89 int Precede(char a,char b)//a为符号栈栈顶元素,b为待插入的元素
     90 {
     91     int i;//i=1入栈,i=0弹出操作符以及操作数进行计算
     92     if((a=='+'||a=='-')&&(b=='*'||b=='/')) i=1;
     93     if((a=='+'||a=='-')&&(b=='+'||b=='-')) i=0;
     94     if((a=='*'||a=='/')&&(b=='*'||b=='/')) i=0;
     95     if((a=='*'||a=='/')&&(b=='+'||b=='-')) i=0;
     96     if(a=='('||a==')') i=1;
     97     return i;
     98 }
     99 
    100 
    101 int Nifix_To_Suffix(char *p)
    102 {
    103     char a,c,e;
    104     int i;
    105     SqStack S;//S为操作符栈,遇到操作数直接输出,所以不需要操作数栈
    106     InitStack(S);
    107     c=*p++;
    108     cout<<"转换后的后缀表达式为:"<<endl;
    109     while(c!='#')
    110     {
    111          if(c>=48&&c<=57) cout<<c;//输入为数字,直接输出
    112          if(c=='(') Push(S,c); //输入为左括号
    113          if(c==')')//输入为右括号
    114          {
    115              if(!EmptyStack(S)) GetTop(S,e);
    116              while(e!='(')
    117              {
    118                  Pop(S,a);cout<<a;
    119                  if(!EmptyStack(S)) GetTop(S,e);//直到遇到左括号
    120                  if(e=='(') Pop(S,e);
    121              }
    122          }
    123          if(c=='+'||c=='-'||c=='*'||c=='/')
    124          {
    125              if(EmptyStack(S))  Push(S,c);
    126              else
    127              {
    128                  GetTop(S,e);
    129                  i=Precede(e,c);
    130                  if(i==1) Push(S,c);
    131                  if(i==0)
    132                  {
    133                      while(!i)
    134                      {
    135                          Pop(S,a); cout<<a;
    136                          if(!EmptyStack(S)) {GetTop(S,e); i=Precede(e,c);}
    137                          else break;
    138                      }
    139                      Push(S,c);
    140                  }
    141              }
    142          }
    143          c=*p++;
    144     }
    145     if(!EmptyStack(S))
    146     {
    147         while(!EmptyStack(S))
    148         {
    149              Pop(S,a);
    150              cout<<a;
    151         }
    152     }
    153     cout<<endl;
    154     return 0;
    155 }
    156 
    157 
    158 int Nifix_To_Prefix (char *p)
    159 {
    160     char a,c,d,e;
    161     int i;
    162     SqStack S,S1,S2;//S为操作符栈,S1为存储倒置后元素的栈,S2存储的是逆序的前缀表达式,最后依次弹出以实现最终的前缀表达式
    163     InitStack(S);InitStack(S1);InitStack(S2);
    164     //由于要从右到左依次读取表达式中的各个元素,所以这里利用一个栈S1将它们倒置
    165     d='#';
    166     Push(S1,d);
    167     while(*p!='#')
    168     {
    169         d=*p;
    170         Push(S1,d);
    171         p++;
    172         if(*p=='#') break;
    173     }
    174     Pop(S1,c);
    175     cout<<"转换后的前缀表达式为:"<<endl;
    176     while(c!='#')
    177     {
    178          if(c>=48&&c<=57) Push(S2,c);//输入为数字,直接输出
    179          if(c==')') Push(S,c); //输入为右括号
    180          if(c=='(')//输入为左括号
    181          {
    182              if(!EmptyStack(S)) GetTop(S,e);
    183              while(e!=')')
    184              {
    185                  Pop(S,a);Push(S2,a);
    186                  if(!EmptyStack(S)) GetTop(S,e);//直到遇到左括号
    187                  if(e==')') Pop(S,e);
    188              }
    189          }
    190          if(c=='+'||c=='-'||c=='*'||c=='/')
    191          {
    192              if(EmptyStack(S))  Push(S,c);
    193              else
    194              {
    195                  GetTop(S,e);
    196                  i=Precede(e,c);
    197                  if(i==1) Push(S,c);
    198                  if(i==0)
    199                  {
    200                      while(!i)
    201                      {
    202                          Pop(S,a); Push(S2,a);
    203                          if(!EmptyStack(S)) {GetTop(S,e); i=Precede(e,c);}
    204                          else break;
    205                      }
    206                      Push(S,c);
    207                  }
    208              }
    209          }
    210          Pop(S1,c);
    211     }
    212     if(!EmptyStack(S))
    213     {
    214         while(!EmptyStack(S))
    215         {
    216              Pop(S,a);
    217              Push(S2,a);
    218         }
    219     }
    220     while(!EmptyStack(S2))
    221     {
    222         Pop(S2,a);
    223         cout<<a;
    224     }
    225     cout<<endl;
    226     return 0;
    227 }
    228 
    229 
    230 
    231 
    232 int main()
    233 {
    234     //数据测试
    235     char *p1="3+2*5#";
    236     char *p2="2*5+3#";
    237     char *p3="2+3*(5-1)#";
    238     char *p4="((3+5*2)+2)/5+6/3*2+3#";
    239     char *p5="2+(3+4)*5#";
    240     cout<<"3+2*5"<<endl; Nifix_To_Suffix(p1); Nifix_To_Prefix(p1);cout<<endl<<endl;
    241     cout<<"2*5+3"<<endl; Nifix_To_Suffix(p2); Nifix_To_Prefix(p2);cout<<endl<<endl;
    242     cout<<"2+3*(5-1)"<<endl; Nifix_To_Suffix(p3); Nifix_To_Prefix(p3);cout<<endl<<endl;
    243     cout<<"((3+5*2)+2)/5+6/3*2+3"<<endl; Nifix_To_Suffix(p4); Nifix_To_Prefix(p4);cout<<endl<<endl;
    244     cout<<"2+(3+4)*5"<<endl; Nifix_To_Suffix(p5); Nifix_To_Prefix(p5);cout<<endl<<endl;
    245     return 0;
    246 }
    只有0和1的世界是简单的
  • 相关阅读:
    【从0开始学架构】架构设计三原则
    【Linux网络】端口
    【Python连接数据库】Python连接Teradata数据库-TD SQL Driver 方式(teradatasql包)
    【Python实战】python中含有中文字符无法运行
    【Linux基础】linux updatedb命令
    【Linux基础】查看和更改当前系统字符集(LC_ALL、LC_TYPE和LANG)
    【数据库】ODBC与JDBC
    LNMP安装目录及配置文件位置
    Linux Vi 的使用
    C#VS2017添加ReportViewer控件
  • 原文地址:https://www.cnblogs.com/nullxjx/p/5940030.html
Copyright © 2011-2022 走看看