zoukankan      html  css  js  c++  java
  • 表达式求值

    前两天翻看《数据结构》,看到有个表达式求值的东西比较有意思。于是乎就用c#代码实现了下。倒腾了半天 总算能工作了。 看到博客园的前辈们也写过好多类似的例子 献丑了。程序设计语言中都有计算表达式的问题,这是语言编译中的典型问题。看到博客园的其他帖子好多都是说什么后缀表达式 什么的。我这个代码比较短 但是基础功能是完全实现了的。

    《数据结构》第3章63 页 是讲堆栈。就是stack 这个鸟玩意儿 。以前存数据 都是用list 类似于链表 。谁用过这个啊 有什么用。没什么用 就是一种数据结构。表达式求值这当中利用了一个重要特性 那就是堆栈的先进后出。 不论是我们的高级程序语言 还是表达式  ,他们都有一个重要的特性就是 大括号包小括号  括号当中包括号。并且有左括号就会有右括号 是相互对称的 ,其实要说的话 这个是一种递归结构。 不管怎么说  遇左括号入栈  遇右括号出栈  ,堆栈天生就有一种处理这种问题的能力,并且还让条理更清晰。

    我这段代码的大概原理就是书上讲的那样:

    先给个运算符优先级表

    1 char[,] compareTable = new char[7, 7]{
    2             {'>','>','<','<','<','>','>'},
    3             {'>','>','<','<','<','>','>'},
    4             {'>','>','>','>','<','>','>'},
    5             {'>','>','>','>','<','>','>'},
    6             {'<','<','<','<','<','=','x'},
    7             {'>','>','>','>','x','>','>'},
    8             {'<','<','<','<','<','x','='}
    9             };

    横着竖着7行7列  依次对应+-*/()#   行数为第一个变量 列数为第二个变量 ,比如+与* 为 compare[0,2] 是小于符号 ,+号优先级小于*
    然后是规则:
    从左往右扫描,遇操作数进operator栈 遇操作符进行下面的逻辑
    1若栈顶运算符优先级低于刚读入的运算符 则让刚读入的运算符进入operator栈
    2若栈顶运算符的优先级高于刚读入的运算符则将栈顶运算符退栈 ,同时将操作数栈operand退栈两次 让他们进行运算 运算结果推入operator栈
    3若优先级相同 说明左右括号相遇 只需将栈顶运算符退栈即可
    当栈顶操作符和刚读入操作符均为#时 说明表达式结束

    就这样如此往复 遇到一个小的计算单位就会自动求值并消除操作数和操作符  然后又让求出的值和其他值进行运算 如此往复以小到大都求出整个表达式的值。

      1 public char compareOper(char opr1, char opr2)
      2         {
      3             char[,] compareTable = new char[7, 7]{
      4             {'>','>','<','<','<','>','>'},
      5             {'>','>','<','<','<','>','>'},
      6             {'>','>','>','>','<','>','>'},
      7             {'>','>','>','>','<','>','>'},
      8             {'<','<','<','<','<','=','x'},
      9             {'>','>','>','>','x','>','>'},
     10             {'<','<','<','<','<','x','='}
     11             };
     12 
     13             int opr1Indx = 0;
     14             switch (opr1)
     15             {
     16                 case '+':
     17                     opr1Indx = 0;
     18                     break;
     19                 case '-':
     20                     opr1Indx = 1;
     21                     break;
     22                 case '*':
     23                     opr1Indx = 2;
     24                     break;
     25                 case '/':
     26                     opr1Indx = 3;
     27                     break;
     28                 case '(':
     29                     opr1Indx = 4;
     30                     break;
     31                 case ')':
     32                     opr1Indx = 5;
     33                     break;
     34                 case '#':
     35                     opr1Indx = 6;
     36                     break;
     37                 default:
     38                     break;
     39             }
     40             int opr2Indx = 0;
     41             switch (opr2)
     42             {
     43                 case '+':
     44                     opr2Indx = 0;
     45                     break;
     46                 case '-':
     47                     opr2Indx = 1;
     48                     break;
     49                 case '*':
     50                     opr2Indx = 2;
     51                     break;
     52                 case '/':
     53                     opr2Indx = 3;
     54                     break;
     55                 case '(':
     56                     opr2Indx = 4;
     57                     break;
     58                 case ')':
     59                     opr2Indx = 5;
     60                     break;
     61                 case '#':
     62                     opr2Indx = 6;
     63                     break;
     64                 default:
     65                     break;
     66             }
     67 
     68             return compareTable[opr1Indx, opr2Indx];
     69         }
     70         public int calc(int num1, int num2, char opr)
     71         {
     72             switch (opr)
     73             {
     74                 case '+':
     75                     return num1 + num2;
     76                     break;
     77                 case '-':
     78                     return num1 - num2;
     79                     break;
     80                 case '*':
     81                     return num1 * num2;
     82                     break;
     83                 case '/':
     84                     return num1 / num2;
     85                     break;
     86 
     87                 default:
     88                     break;
     89             }
     90             return 0;
     91         }
     92         private void button1_Click(object sender, EventArgs e)
     93         {
     94             Stack<int> operand = new Stack<int>();
     95             Stack<char> opera = new Stack<char>();
     96             opera.Push('#');
     97 
     98             string exp = textBox1.Text;
     99 
    100             Regex numVali = new Regex(@"d");
    101 
    102             //MessageBox.Show(numVali.IsMatch("6").ToString());
    103 
    104             for (int i = 0; i < exp.Length; i++)
    105             {
    106                 if (numVali.IsMatch(exp[i] + "") == true || exp[i] == ' ')//数字
    107                 {
    108                     string numTmp = exp[i] + "";
    109                     int nextNumIndx = 1;
    110                     char nextNum = exp[i + (nextNumIndx)];
    111                     nextNumIndx++;
    112                     while (numVali.IsMatch(nextNum + "") == true || nextNum == ' ')
    113                     {
    114                         numTmp += nextNum;
    115                         if (i + (nextNumIndx) < exp.Length)
    116                         {
    117                             nextNum = exp[i + (nextNumIndx)];
    118                             nextNumIndx++;
    119                         }
    120                         else
    121                             break;
    122                     }
    123                     operand.Push(int.Parse(numTmp.Replace(" ", "")));
    124                     i = i + nextNumIndx - 1 - 1;
    125 
    126                 }
    127                 else//操作符
    128                 {
    129 
    132                     switch (compareOper(opera.Peek(), exp[i]))
    133                     {
    134                         case '<':
    135                             opera.Push(exp[i]);
    136                             break;
    137                         case '=':
    138                             opera.Pop();
    139                             break;
    140                         case '>':
    141 
    142                             int b = operand.Pop();
    143                             int a = operand.Pop();
    144                             operand.Push(calc(a, b, opera.Pop()));
    145 
    146  
    147                             if (compareOper(opera.Peek(), exp[i]) == '=')
    148                             {
    149                                 opera.Pop();
    150                             }
    151                             else if (compareOper(opera.Peek(), exp[i]) == '>')
    152                             {
    153                                  b = operand.Pop();
    154                                  a = operand.Pop();
    155                                 operand.Push(calc(a, b, opera.Pop()));
    156                                 //opera.Push(exp[i]);
    157 
    158                                 if (compareOper(opera.Peek(), exp[i]) == '=')
    159                                 {
    160                                     opera.Pop();
    161                                 }
    162                                 else if (compareOper(opera.Peek(), exp[i]) == '>')
    163                                 {
    164                                     b = operand.Pop();
    165                                     a = operand.Pop();
    166                                     operand.Push(calc(a, b, opera.Pop()));
    167                                     opera.Push(exp[i]);
    168                                 }
    169                                 else if (compareOper(opera.Peek(), exp[i]) == '<')
    170                                     opera.Push(exp[i]);
    171                             }
    172                             else if (compareOper(opera.Peek(), exp[i]) == '<')
    173                                 opera.Push(exp[i]);
    174                             break;
    175                         default:
    176                             break;
    177                     }
    178                     if (exp[i] == '#')
    179                         break;
    180                 }
    181             }
    182             MessageBox.Show(string.Format("结果是{0}", operand.Peek()));
    183         }


    就这样了 ,亲测 可用。暂时只能计算整数哈,一个正确的输入 应该像这样:(3+2)*4#   。以井号结尾

    最后测试了 下自己写的还是有点小问题 ,火力还是不够啊  。 这是网上找的一个别人写的:

      1 public void calcM(string s)
      2         {
      3             int kuohaoCount=0;
      4             foreach (var item in s)
      5             {
      6                 if (item == '(' || item == ')')
      7                     kuohaoCount++;
      8             }
      9             if (kuohaoCount % 2 != 0)
     10             {
     11                 MessageBox.Show("公式里括号个数不合法");
     12                 return;
     13             }
     14             else if(s.IndexOf('=')>=0)
     15             {
     16                 MessageBox.Show("公式里不能出现等号");
     17                 return;
     18             }
     19 
     20             s = s.ToUpper();
     21             s=s.Replace('A', '1');
     22             s = s.Replace('B', '1');
     23             s = s.Replace('C', '1');
     24 
     25             try
     26             {
     27                 string S = ""; //后缀
     28                 char[] Operators = new char[s.Length];
     29                 int Top = -1;
     30                 for (int i = 0; i < s.Length; i++)
     31                 {
     32                     char C = s[i];
     33                     switch (C)
     34                     {
     35                         case ' ': //忽略空格
     36                             break;
     37                         case '+': //操作符
     38                         case '-':
     39                             while (Top >= 0) //栈不为空时
     40                             {
     41                                 char c = Operators[Top--]; //pop Operator
     42                                 if (c == '(')
     43                                 {
     44                                     Operators[++Top] = c; //push Operator
     45                                     break;
     46                                 }
     47                                 else
     48                                 {
     49                                     S = S + c;
     50                                 }
     51                             }
     52                             Operators[++Top] = C; //push Operator
     53                             S += " ";
     54                             break;
     55                         case '*': //忽略空格
     56                         case '/':
     57                             while (Top >= 0) //栈不为空时
     58                             {
     59                                 char c = Operators[Top--]; //pop Operator
     60                                 if (c == '(')
     61                                 {
     62                                     Operators[++Top] = c; //push Operator
     63                                     break;
     64                                 }
     65                                 else
     66                                 {
     67                                     if (c == '+' || c == '-')
     68                                     {
     69                                         Operators[++Top] = c; //push Operator
     70                                         break;
     71                                     }
     72                                     else
     73                                     {
     74                                         S = S + c;
     75                                     }
     76                                 }
     77                             }
     78                             Operators[++Top] = C; //push Operator
     79                             S += " ";
     80                             break;
     81                         case '(':
     82                             Operators[++Top] = C;
     83                             S += " ";
     84                             break;
     85                         case ')':
     86                             while (Top >= 0) //栈不为空时
     87                             {
     88                                 char c = Operators[Top--]; //pop Operator
     89                                 if (c == '(')
     90                                 {
     91                                     break;
     92                                 }
     93                                 else
     94                                 {
     95                                     S = S + c;
     96                                 }
     97                             }
     98                             S += " ";
     99                             break;
    100                         default:
    101                             S = S + C;
    102                             break;
    103 
    104                     }
    105                 }
    106                 while (Top >= 0)
    107                 {
    108                     S = S + Operators[Top--]; //pop Operator
    109                 }
    110 
    111                 //System.Console.WriteLine(S); //后缀
    112 
    113                 //后缀表达式计算
    114                 double[] Operands = new double[S.Length];
    115                 double x, y, v;
    116                 Top = -1;
    117                 string Operand = "";
    118                 for (int i = 0; i < S.Length; i++)
    119                 {
    120                     char c = S[i];
    121                     if ((c >= '0' && c <= '9') || c == '.')
    122                     {
    123                         Operand += c;
    124                     }
    125 
    126                     if ((c == ' ' || i == S.Length - 1) && Operand != "") //Update
    127                     {
    128                         Operands[++Top] = System.Convert.ToDouble(Operand); //push Operands
    129                         Operand = "";
    130                     }
    131 
    132                     if (c == '+' || c == '-' || c == '*' || c == '/')
    133                     {
    134                         if ((Operand != ""))
    135                         {
    136                             Operands[++Top] = System.Convert.ToDouble(Operand); //push Operands
    137                             Operand = "";
    138                         }
    139                         y = Operands[Top--]; //pop 双目运算符的第二操作数 (后进先出)注意操作数顺序对除法的影响
    140                         x = Operands[Top--]; //pop 双目运算符的第一操作数
    141                         switch (c)
    142                         {
    143                             case '+':
    144                                 v = x + y;
    145                                 break;
    146                             case '-':
    147                                 v = x - y;
    148                                 break;
    149                             case '*':
    150                                 v = x * y;
    151                                 break;
    152                             case '/':
    153                                 v = x / y; // 第一操作数 / 第二操作数 注意操作数顺序对除法的影响
    154                                 break;
    155                             default:
    156                                 v = 0;
    157                                 break;
    158                         }
    159                         Operands[++Top] = v; //push 中间结果再次入栈
    160                     }
    161                 }
    162                 v = Operands[Top--]; //pop 最终结果
    163                 MessageBox.Show("结果是:" + v);
    164             }
    165             catch (System.Exception ex)
    166             {
    167                 MessageBox.Show("公式解析出现错误");
    168                
    169             }
    170             
    171         }
  • 相关阅读:
    Exp7 网络欺诈防范
    Exp6 信息搜集与漏洞扫描
    Exp4 恶意代码分析
    Exp2 后门原理与实践
    PC平台逆向破解实验报告
    See You Again——我最后的汇编程序
    表格标签
    ansible环境搭建
    OSPF_1
    Linux的文件管理(8-27)
  • 原文地址:https://www.cnblogs.com/assassinx/p/4423746.html
Copyright © 2011-2022 走看看