栈的应用——表达式求值

      最开始做表达式求值的时候,思路不太清晰,后来想了想,有两种方式:方式一:先把中缀表达式转成后缀表达式,然后再求值就方便多了;方式二:算符优先方式。
      发觉细节处理上很麻烦,最开始打算用C写,用自己的栈。后来发现自己的栈跟数据类型有密切联系,由于不能用模板,所以两个不同数据类型的栈操作要实现两次,最后想到了用void*指针指向实际的数据,用的时候再转换,感觉增加了复杂度,又降低了效率,所以直接用C++的stack。
     另外一个问题就是输入方式,一种用getchar(),但识别的时候由于要超前读取一个字符,所以要设置缓冲区。另一种是直接读入一行字符串,缺点是受到了数组大小的限制。本次采用的是第二种。
     在对字符的处理方式上,这里选用获取到相应运算数时,存入字符数组,然后转换成double型。另一种就是变读入边处理,直接返回double型。
      整体思路如下:
      1、设置两个栈,一个称作optr,用于寄存运算符,另一个称作opnd,用于寄存操作数或运算结果。
      2、从str字符数组开始扫描,若是操作数则进opnd栈,若是运算符则和optr栈的栈顶运算符比较优先级后作相应操作。直到整个表达式求职完毕(optr和当前读入的字符均为'=')。
      代码如下:

Code:
  1. #include <iostream>   
  2. #include <stack>   
  3. #include <cctype>   
  4. using namespace std;   
  5.   
  6. #define MAXVAL 100 /* the max length of input string */   
  7. #define NUMBER '0' /* mark for find a number */   
  8.   
  9. char getop(char s[], char str[])   
  10. {   
  11.     char c;   
  12.     int i;   
  13.     static int j = 0;   
  14.        
  15.     i = 0;   
  16.     while ((s[0] = c = str[j]) == ' ' || c == '/t')   
  17.         j++;   
  18.     s[1] = '/0';   
  19.        
  20.     if (! isdigit(c) && c != '.') {   
  21.         j++;   
  22.         return c;   
  23.     }   
  24.     if (isdigit(c)) {   
  25.         while (isdigit(s[++i] = c = str[++j]))   
  26.             ;   
  27.     }   
  28.     if (c == '.') {   
  29.         while(isdigit(s[++i] = c = str[++j]))   
  30.             ;   
  31.     }   
  32.     s[i] = '/0';   
  33.     return NUMBER;   
  34. }   
  35.   
  36. int index(char c)   
  37. {   
  38.     int ret;   
  39.     switch (c) {   
  40.     case '+':   
  41.         ret = 0;   
  42.         break;   
  43.     case '-':   
  44.         ret = 1;   
  45.         break;   
  46.     case '*':   
  47.         ret = 2;   
  48.         break;   
  49.     case '/':   
  50.         ret = 3;   
  51.         break;   
  52.     case '(':   
  53.         ret = 4;   
  54.         break;   
  55.     case ')':   
  56.         ret = 5;   
  57.         break;   
  58.     case '=':   
  59.         ret = 6;   
  60.         break;   
  61.     default:   
  62.         break;   
  63.     }   
  64.     return ret;   
  65. }   
  66.   
  67. char precede(char top, char c, char priority[][7])   
  68. {   
  69.     int i = 0, j =0;   
  70.     i = index(top);   
  71.     j = index(c);   
  72.     return priority[i][j];   
  73. }   
  74.   
  75. double operate(double a, char op, double b)   
  76. {   
  77.     double ret = 0;   
  78.     switch (op) {   
  79.     case '+':   
  80.         ret = a + b;   
  81.         break;   
  82.     case '-':   
  83.         ret = a - b;   
  84.         break;   
  85.     case '*':   
  86.         ret = a * b;   
  87.         break;   
  88.     case '/':   
  89.         ret = a / b;   
  90.         break;   
  91.     default:   
  92.         break;   
  93.     }   
  94.     return ret;    
  95. }   
  96.        
  97. double evaluate_expression(char *str, char priority[][7])   
  98. {   
  99.     stack<double> opnd;   
  100.     stack<char> optr;   
  101.     char c, s[MAXVAL], op, ch;   
  102.     double a, b;   
  103.        
  104.     optr.push('=');   
  105.     c = getop(s, str);   
  106.     while (c != '=' || optr.top() != '=') {   
  107.         if (c == NUMBER) {   
  108.             opnd.push(atof(s));   
  109.             c = getop(s, str);   
  110.         } else {   
  111.             switch (ch = precede(optr.top(), c, priority)) {   
  112.             case '<'/* the top element of stack optr has lower priority */  
  113.                 optr.push(c);   
  114.                 c = getop(s, str);   
  115.                 break;   
  116.             case '='/* get off '(' and get next character */  
  117.                 optr.pop();   
  118.                 c = getop(s, str);   
  119.                 break;   
  120.             case '>'/* pop and push compute result */  
  121.                 op = optr.top();   
  122.                 optr.pop();   
  123.                 b = opnd.top();   
  124.                 opnd.pop();   
  125.                 a = opnd.top();   
  126.                 opnd.pop();   
  127.                 opnd.push(operate(a, op, b));   
  128.                 break;   
  129.             default:   
  130.                 break;   
  131.             }   
  132.         }   
  133.     }   
  134.     return opnd.top();   
  135. }   
  136.   
  137. int main()   
  138. {   
  139.     char str[MAXVAL];   
  140.     char priority[7][7] = {   
  141.       // +   -     *    /    (    )    =   
  142.         '>''>''<''<''<''>''>'// +   
  143.         '>''>''<''<''<''>''>'// -   
  144.         '>''>''>''>''<''>''>'// *   
  145.         '>''>''>''>''<''>''>'// /   
  146.         '<''<''<''<''<''='' '// (   
  147.         '>''>''>''>'' ''>''>'// )   
  148.         '<''<''<''<''<'' ''='  // =   
  149.     };   
  150.     gets(str);   
  151.     double ret = evaluate_expression(str, priority);   
  152.     printf("%g/n", ret);   
  153.     return 0;   
  154. }   

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值