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

    逆波兰表达式

    先说一下中缀表达式,平时我们使用的运算表达式就是中缀表达式,例如1+3*2,中缀表达式的特点就是:二元运算符总是置于与之相关的两个运算对象之间

    人读起来比较好理解,但是计算机处理起来就很麻烦,运算顺序往往因表达式的内容而定,不具规律性

    后缀表达式,后缀表达式的特点就是:每一运算符都置于其运算对象之后,以上面的中缀表达式1+2*3为例子,转为后缀表达式就是123*+

    下面先分析怎么把中缀表达式转换为后缀表达式,这里我们考虑六种操作符'+'、'-'、'*'、'/'、'('、')',完成中缀转后缀我们需要两个数组,都以栈的方式来操作,一个数组用来存放后缀表达式(char num[100]),

    一个数组用来临时存放操作数(char opera[100])(这里说临时存放,是因为最后都要入栈到后缀表达式数组num中,这个数组就相当于一个中转站)

    1、从左往右扫描中缀表达式(这里我们以1*(2+3)为例)

    2、如果是数字那么将其直接入栈到数组num

    3、如果是操作数,需要进一步判断

    (1)如果是左括号'('直接入栈到数组opera

    (2)如果是运算符('+'、'-'、'*'、'/'),先判断数组opera栈顶的操作数的优先级(如果是空栈那么直接入栈到数组opera),如果是左括号那么直接入栈到数组opera中,如果栈顶是运算符,且栈顶运算符的优先级大于该运算符

    那么将栈顶的运算符出栈,并入栈到数组num中,重复步骤3,如果栈顶运算符优先级小于该运算符,那么直接将该运算符入栈到opera中

    (3)如果是右括号')',那么说明在opera数组中一定有一个左括号与之对应(在你没输错的情况下),那么将opera中的运算符依次出栈,并入栈到num中,直到遇到左括号'('(注意左括号不用入栈到num

    4、如果中缀表达式扫描完了,那么将opera中的操作数依次出栈,并入栈到num中就可以了,如果没有没有扫描完重复1-3步

    上面就是中缀表达式转后缀表达式的步骤了,下面用图来直观的了解一下这个过程

    需要注意的是:opera中操作数,越靠近栈顶,优先级越高,下面附上实现代码

      1 void PexpretoSexpre(char *ss)
      2 {
      3     char num[100] = "0";    /* 存储后缀表达式 */
      4     char opera[100] = "0";    /* 存储运算符 */
      5     /*
      6     num----j
      7     opera----op
      8     ss----i
      9     */
     10     int i, j, op;
     11 
     12     op = i = j = 0;
     13 
     14     while (ss[i] != '')
     15     {
     16         if (isdigit(ss[i]))    /* 如果是数字 */
     17         {
     18             num[j] = ss[i];    /* 数字直接入后缀表达式栈 */
     19             j++;
     20             i++;
     21         }
     22         else
     23         {
     24             switch (ss[i])    /* 如果是操作数 */
     25             {
     26             case '+':
     27                 {
     28                     if (op == 0)    /* 如果是空栈 */
     29                     {
     30                         PushOperation(opera, ss, &op, &i);    /* 入运算符栈 */
     31                         break;
     32                     }
     33                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
     34                     {
     35                         switch (opera[op-1])
     36                         {
     37                         case '+':
     38                             {
     39                                 PushOperation(opera, ss, &op, &i);
     40                                 break;
     41                             }
     42                         case '-':
     43                             {
     44                                 PushOperation(opera, ss, &op, &i);
     45                                 break;
     46                             }
     47                         case '*':
     48                             {    /* 加法优先级低于乘法 */
     49                                 num[j] = opera[op-1];    /* 将操作数出栈 */
     50                                 opera[op-1] = ss[i];        /* 将新的操作数压入栈中 */
     51                                 j++;
     52                                 i++;
     53                                 break;
     54                             }
     55                         case '/':
     56                             {
     57                                 num[j] = opera[op-1];
     58                                 opera[op-1] = ss[i];
     59                                 j++;
     60                                 i++;
     61                                 break;
     62                             }
     63                         case '(':
     64                             {
     65                                 PushOperation(opera, ss, &op, &i);
     66                                 break;
     67                             }
     68                         }
     69                     }
     70                     break;
     71                 }
     72             case '-':
     73                 {
     74                     if (op == 0)
     75                     {
     76                         PushOperation(opera, ss, &op, &i);
     77                         break;
     78                     }
     79                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
     80                     {
     81                         switch (opera[op-1])
     82                         {
     83                         case '+':
     84                             {
     85                                 PushOperation(opera, ss, &op, &i);
     86                                 break;
     87                             }
     88                         case '-':
     89                             {
     90                                 PushOperation(opera, ss, &op, &i);
     91                                 break;
     92                             }
     93                         case '*':
     94                             {
     95                                 num[j] = opera[op-1];
     96                                 opera[op-1] = ss[i];
     97                                 j++;
     98                                 i++;
     99                                 break;
    100                             }
    101                         case '/':
    102                             {
    103                                 num[j] = opera[op-1];
    104                                 opera[op-1] = ss[i];
    105                                 j++;
    106                                 i++;
    107                                 break;
    108                             }
    109                         case '(':
    110                             {
    111                                 PushOperation(opera, ss, &op, &i);
    112                                 break;
    113                             }
    114                         }
    115                     }
    116                     break;
    117                 }
    118             case '*':
    119                 {
    120                     if (op == 0)
    121                     {
    122                         PushOperation(opera, ss, &op, &i);
    123                         break;
    124                     }
    125                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
    126                     {
    127                         switch (opera[op-1])
    128                         {
    129                         case '+':
    130                             {
    131                                 PushOperation(opera, ss, &op, &i);
    132                                 break;
    133                             }
    134                         case '-':
    135                             {
    136                                 PushOperation(opera, ss, &op, &i);
    137                                 break;
    138                             }
    139                         case '*':
    140                             {
    141                                 PushOperation(opera, ss, &op, &i);
    142                                 break;
    143                             }
    144                         case '/':
    145                             {
    146                                 PushOperation(opera, ss, &op, &i);
    147                                 break;
    148                             }
    149                         case '(':
    150                             {
    151                                 PushOperation(opera, ss, &op, &i);
    152                                 break;
    153                             }
    154                         }
    155                     }
    156                     break;
    157                 }
    158             case '/':
    159                 {
    160                     if (op == 0)
    161                     {
    162                         PushOperation(opera, ss, &op, &i);
    163                         break;
    164                     }
    165                     if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(')
    166                     {
    167                         switch (opera[op-1])
    168                         {
    169                         case '+':
    170                             {
    171                                 PushOperation(opera, ss, &op, &i);
    172                                 break;
    173                             }
    174                         case '-':
    175                             {
    176                                 PushOperation(opera, ss, &op, &i);
    177                                 break;
    178                             }
    179                         case '*':
    180                             {
    181                                 PushOperation(opera, ss, &op, &i);
    182                                 break;
    183                             }
    184                         case '/':
    185                             {
    186                                 PushOperation(opera, ss, &op, &i);
    187                                 break;
    188                             }
    189                         case '(':
    190                             {
    191                                 PushOperation(opera, ss, &op, &i);
    192                                 break;
    193                             }
    194                         }
    195                     }
    196                     break;
    197                 }
    198             case '(':
    199                 {
    200                     PushOperation(opera, ss, &op, &i);
    201                     break;
    202                 }
    203             case ')':    /* 如果遇到右括号 */
    204                 {
    205                     while (opera[op-1] != '(')
    206                     {
    207                         num[j] = opera[op-1];    /* 将运算符栈中的元素依次入栈到后缀表达式栈中,直到遇到左括号为止 */
    208                         j++;
    209                         op--;
    210                     }
    211                     op--;
    212                     i++;
    213                     break;
    214                 }
    215             default:
    216                 {
    217                     printf("传入表达式不符合要求
    ");
    218                     exit(0);
    219                 }
    220                     
    221             }
    222         }
    223     }
    224     while (op != 0)
    225     {
    226         num[j] = opera[op-1];    /* 将运算符栈中的元素依次入栈到后缀表达式栈中 */
    227         j++;
    228         op--;
    229     }
    230     num[j] = '';
    231     i = 0;
    232     while (num[i] != '')    /* 将后缀表达式存储到传入的形参ss中 */
    233     {
    234         ss[i] = num[i];
    235         i++;
    236     }
    237     ss[i] = '';
    238 }
    239 
    240 /* Function: 入运算符栈*/
    241 void PushOperation(char *opera, char *ss, int *op, int *s)
    242 {
    243     opera[*op] = ss[*s];
    244     (*op)++;
    245     (*s)++;
    246 }
    View Code

    后缀表达式的计算

    完成了中缀表达式转后缀表达式,接下来就是后缀表达式的计算了,后缀表达式的计算比中缀转后缀要稍微简单一点,只需要对我们转换好的后缀表达式从左往右依次扫描,并依次入栈就行了,

    意思是只需要用一个数组(double num[100])就OK了

    需要考虑的情况如下

    1、如果是数字,那么直接入栈到num中

    2、如果是运算符,将栈顶的两个数字出栈(因为我们考虑的运算符加、减、乘、除都是双目运算符,只需要两个操作数),出栈后对两个数字进行相应的运算,并将运算结果入栈

    3、直到遇到''

    下面用几张图,来直观了解下这个过程,以上面转换好的后缀表达式"123+*"为例(这里用ss来存储后缀表达式,num来存储计算结果,注意不要与上面图中num搞混淆了)

    (注意:这里将计算结果5入栈后,栈顶从之前的[3]变成[2])

    到这里后缀表达式的计算就结束了,下面附上实现代码

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 #define MAX 100
      5 
      6 void JudgeFopen_s(errno_t err);        /* 判断文件打开是否成功 */
      7 void ReadFile(FILE *fp, char *ss);    /* 读取文件内容 */
      8 double TransformCtoD(char ch);        /* 将char类型数组的每一个元素转换为double */
      9 void CalculateAndPush(double *num, int *i, int *j, char mm);    /* 计算结果并入栈 */
     10 
     11 int main()
     12 {
     13     FILE *fp;
     14     errno_t err;
     15 
     16     char ss[MAX];    /* 存储逆波兰表达式 */
     17     int i = 0;
     18     int j = 0;
     19     double num[MAX];    /**/
     20     
     21     err = fopen_s(&fp, "E:\ww.txt", "r");
     22 
     23     JudgeFopen_s(err);    /* 判断文件打开是否成功 */
     24     ReadFile(fp, ss);    /* 读取文件内容,存储到ss中*/
     25 
     26     while (ss[i] != '')
     27     {
     28         if (ss[i] >= '0' && ss[i] <= '9')    /* 如果是数字 */
     29         {
     30             /* 因为num是char类型的,需要转换为double类型方便计算 */
     31             num[j] = TransformCtoD(ss[i]);    /* 将数字存储到栈中 */
     32             j++;
     33             i++;
     34         }
     35         else if (ss[i] == '+' || ss[i] == '-' || ss[i] == '*' || ss[i] == '/')
     36         {
     37             CalculateAndPush(num, &i, &j, ss[i]);    /* 计算结果并入栈 */
     38         }
     39         else if (ss[i] == '
    ')    /* 如果是换行符,结束循环*/
     40         {
     41             break;
     42         }
     43     }
     44 
     45     printf("%lf", num[0]);
     46 
     47     return 0;
     48 }
     49 
     50 /* Function: 计算结果并入栈 */
     51 void CalculateAndPush(double *num, int *i, int *j, char mm)
     52 {
     53     switch (mm)
     54     {
     55     case '+':
     56         {
     57             num[(*j)-2] = num[(*j)-1] + num[(*j)-2];
     58             (*j)--;
     59             (*i)++;
     60             break;
     61         }
     62     case '-':
     63         {
     64             num[(*j)-2] = num[(*j)-1] - num[(*j)-2];
     65             (*j)--;
     66             (*i)++;
     67             break;
     68         }
     69     case '*':
     70         {
     71             num[(*j)-2] = num[(*j)-1] * num[(*j)-2];
     72             (*j)--;
     73             (*i)++;
     74             break;
     75         }
     76     case '/':
     77         {
     78             num[(*j)-2] = num[(*j)-1] / num[(*j)-2];
     79             (*j)--;
     80             (*i)++;
     81             break;
     82         }
     83     default:
     84         {
     85             exit(0);
     86         }
     87     }
     88 }
     89 /* Function: 判断文件打开是否成功 */
     90 void JudgeFopen_s(errno_t err)
     91 {
     92     if (err != 0)
     93     {
     94         printf("文件打开失败
    ");
     95         system("pause");
     96         exit(0);
     97     }
     98 }
     99 
    100 /* Function: 读取文件内容*/
    101 void ReadFile(FILE *fp, char *ss)
    102 {
    103     int i = 0;
    104 
    105     while (!feof(fp))
    106     {
    107         fscanf_s(fp, "%c", &ss[i]);
    108         i++;
    109     }
    110     ss[i-1] = '';
    111 }
    112 
    113 /* Function: 将char类型数组的每一个元素转换为double */
    114 double TransformCtoD(char ch)
    115 {
    116     return (double)(ch - '0');
    117 }
    View Code
  • 相关阅读:
    javascript定义类和实例化类
    c# 注册表操作,创建,删除,修改,判断节点是否存在
    asp.net 获得文件属性中的修改时间,获得系统文件属性的方法,最后一次写入时间
    研究“QQ开心农场”一点心得
    c# winform socket网络编程,点对点传输文件,socket文件传输,监听端口
    用C#创建Windows服务(Windows Services)
    c# webform js文件获取客户端控件,后台cs获取前台客户端控件的值,c#和js的交互
    c# asp.net webform web页面打印,可以控制需要打印和不需要打印的位置
    c# asp.net 调用系统设置字体文本框,设置label或页面字体,大小,FontDialog
    c# 计算程序执行时间,计算一段代码执行所用的时间,测试效率
  • 原文地址:https://www.cnblogs.com/lanhaicode/p/10776166.html
Copyright © 2011-2022 走看看