• C# 中实现表达式计算


    C# 中实现表达式计算

    http://blog.csdn.net/yillc/article/details/6844931

    提要:

    1.对上一篇文章的改进:增加括号

    2.改变了 字符串转化成中缀表达式的方法

    一、依旧是数据结构的知识:

    1.将中缀表达式转换成后缀表达式

    设算法的输入为中缀表达式infixExp(字符串),输出结果为postfixExp,是保值的后缀表达式。
    举例:23 + 34 * 45 / (5 + 6 + 7)      转后为后缀:      23  34  45  *  5  6  +  7  +   /  +
    2.算法:
    自左至右扫描infixExp,读入每项并分析其对应的语法成分:
    1)当输入的是操作数,则直接输出到postfixExp中。
    2)当输入的是左括号,则把它压栈。
    3)当输入的是右括号,先判断栈是否为空,若为空则括号不匹配;若非空,则把栈中的项依次弹出,直到遇到第1个左括号为止,将弹出的项输出到postfixExp中(弹出的左括号不输出到postfixExp中),若没有遇到左括号,则括号也不匹配。
    4)当输入的是运算符op( 四则运算+ - */ 之一)时:
    a)循环,当(栈非空 and 栈顶不是左括号 and 栈顶运算符的优先级不低于输入运算符的优先级时),反复操作:将栈顶元素弹出,输出到postfixExp中。
    b)把输入的运算符op压栈。
    5)最后,当中缀表达式infixExp的符号序列全部读入后,在栈中可能还会一些项,它们是原来压入还没有处理的语法成分。对待它们的方法是:把它们依次从栈中弹出,并输出到后缀表达式postfixExp的尾部。

    2.后缀的求值见上一篇文章

    二、将字符串变成中缀表达式,保存到Q1中

    在没有想到很好的算法。就是将字符串进行分割,把数值保存到分割后的数组resSplit中,然后对原来的字符串res遍历,寻找运算符。

    期待找到更好的算法。

    1.  <p> //按钮"="的响应代码  
    2.     protected void ButtonEqual_Click(object sender, EventArgs e)  
    3.     {  
    4.           
    5.         int si=0;  
    6.         int s=1;//s=0时:上一个元素是数字。s=1时,上一个是符号  
    7.     </p><p>        String res = TextBoxResult.Text;  
    8.         char[] str = TextBoxResult.Text.ToCharArray();  
    9.         string[] resSplit = res.Split(new char[] { '+''-''*''/','(',')' });  
    10.    
    11.         try  
    12.         {  
    13.             for (int i = 0; i < str.Length; i++)  
    14.             {  
    15.                 node tmp = new node();//临时节点  
    16.                 if ((str[i]==46||( str[i] - 48 <= 9 && 0 <= str[i] - 48) )&& s == 1)//新加入的元素是数值  
    17.                 {  
    18.                     tmp.sign = false;  
    19.                     while (true )  
    20.                     {  
    21.                         if (resSplit[si] != "")  
    22.                         {  
    23.                             tmp.num = Convert.ToDouble(resSplit[si]);  
    24.                             break;  
    25.                         }  
    26.                         else si++;  
    27.                     }  
    28.                        
    29.                     Q1.Enqueue(tmp);  
    30.                     Label1.Text = Label1.Text + tmp.num;//测试  
    31.                     s = 0;  
    32.                     si++;</p><p>                }  
    33.                 else if ((str[i]==46||( str[i] - 48 <= 9 && 0 <= str[i] - 48)) && s == 0)//新加入的元素是数字,但前面元素也是  
    34.                 {  
    35.                     continue;  
    36.                 }  
    37.                 else  
    38.                 {  
    39.                     tmp.sign = true;  
    40.                     tmp.symbol = str[i];  
    41.                     if (tmp.symbol == '*' || tmp.symbol == '/') tmp.priority = 2;  
    42.                     else if (tmp.symbol == '+' || tmp.symbol == '-') tmp.priority = 1;  
    43.                     s = 1;  
    44.                     Q1.Enqueue(tmp);  
    45.                     Label1.Text = Label1.Text + tmp.symbol;//测试  
    46.                 }  
    47.             }  
    48.             
    49.             change();  
    50.            double r = calculate();  
    51.             if(err==false) Label1.Text = Label1.Text + "=" + r+ "<br />";  
    52.             else           Label1.Text = Label1.Text +"error!<br />";//测试  
    53.         }  
    54.         catch (Exception ew)  
    55.         {  
    56.             Label1.Text = Label1.Text +"error!<br />";//测试  
    57.         }  
    58.     }  
    59. </p>  

    三 中缀-后缀

    1. <p> public void change()//2) 将中缀表达式转换成后缀表达式;  
    2.     {  
    3.         while (Q1.Count != 0)  
    4.         {  
    5.             if (Q1.Peek().sign == false)//是数字,放入队列  
    6.             {  
    7.                 Q2.Enqueue(Q1.Peek());  
    8.             }  
    9.             else  
    10.             {  
    11.                 if (Q1.Peek().symbol == '(')//当输入的是左括号,则把它压栈。  
    12.                     Sc.Push(Q1.Peek());  
    13.                 else if (Q1.Peek().symbol == ')')//当输入的是右括号,  
    14.                 {  
    15.                     if (Sc.Count() == 0)  
    16.                     {  
    17.                         err = true;  
    18.                         break;  
    19.                     }  
    20.                     else  
    21.                     {  
    22.                         while (Sc.Peek().symbol != '(')  
    23.                         {  
    24.                             Q2.Enqueue(Sc.Peek());  
    25.                             Sc.Pop();  
    26.                             if (Sc.Count() == 0)  
    27.                             {  
    28.                                 err = true;  
    29.                                 break;  
    30.                             }  
    31.                         }  
    32.                         if (Sc.Count() != 0)  Sc.Pop();  
    33.                     }  
    34.                 }</p><p>                else  
    35.                 {  
    36.                     while (Sc.Count()!= 0 && Q1.Peek().symbol != '(' && Q1.Peek().priority <= Sc.Peek().priority)  
    37.                     {  
    38.                         Q2.Enqueue(Sc.Peek());  
    39.                         Sc.Pop();  
    40.                     }  
    41.                     Sc.Push(Q1.Peek());  
    42.                 }</p><p>            }  
    43.             Q1.Dequeue();  
    44.         }  
    45.         while (Sc.Count() != 0)  
    46.         {  
    47.             if (Sc.Peek().symbol == '(')  
    48.             {  
    49.                 err = true;  
    50.                 break;  
    51.             }  
    52.             Q2.Enqueue(Sc.Peek());  
    53.             Sc.Pop();  
    54.         }</p><p>  
    55.     }</p>  
    56. 四 后缀求解  
    1. public   double calculate()  
    2.    {  
    3.        Stack<node> stmp = new Stack<node>();  
    4.        double num1 = 0;  
    5.        double num2 = 0;  
    6.        node tmp = new node();  
    7.        while (Q2.Count != 0)  
    8.        {  
    9.            if (Q2.Peek().sign == false)  
    10.            {  
    11.                stmp.Push(Q2.Peek());  
    12.            }  
    13.            else if (Q2.Peek().sign == true)  
    14.            {  
    15.                num2 = stmp.Peek().num;  
    16.                stmp.Pop();  
    17.                num1 = stmp.Peek().num;  
    18.                stmp.Pop();  
    19.                if (Q2.Peek().symbol == '+')  
    20.                {  
    21.                    tmp.num = num1 + num2;  
    22.                    tmp.priority = 1;  
    23.                    tmp.sign = false;  
    24.                }  
    25.                else if (Q2.Peek().symbol == '-')  
    26.                {  
    27.                    tmp.num = num1 - num2;  
    28.                    tmp.priority = 1;  
    29.                    tmp.sign = false;  
    30.                }  
    31.                else if (Q2.Peek().symbol == '*')  
    32.                {  
    33.                    tmp.num = num1 * num2;  
    34.                    tmp.priority = 2;  
    35.                    tmp.sign = false;  
    36.                }  
    37.                else if (Q2.Peek().symbol == '/')  
    38.                {  
    39.                    tmp.num = num1 / num2;  
    40.                    tmp.priority = 2;  
    41.                    tmp.sign = false;  
    42.                }   
    43.                stmp.Push(tmp);  
    44.            }  
    45.            Q2.Dequeue();  
    46.        }  
    47.   
    48.        if (stmp.Count() != 1) err = true;  
    49.   
    50.                  
    51.                return stmp.Peek().num;  
    52.       
    53.   
    54.   
    55.    }  

    五、不足:
    1 随便写了点,代码还很不规范

    2 出现错误时全部报错error!,未进行细分

    3 限制为double型,无法达到高精度

    4 不支持负数,如-6 计算时会出错,需写成:(0-6)

  • 相关阅读:
    C#后台制作之数据库(Access数据库+datagirdview控件显示+串口数据存储)
    Zedboardwebcam设计问题篇(六)opencv处理帧数据之算法改进
    Zedboardwebcam设计问题篇(二)V4l2 Capture Sequence 捕获过程
    Zedboardwebcam设计问题篇(五)opencv处理帧数据,函数代码实现
    Zedboardwebcam设计问题篇(七)NFS服务器配置
    Zedboard摄像头获取视频设计问题篇(四)OpenCV+QT配置显示图片
    C#后台制作之数据库(二、如何清除显示以及将数据库数据导出到excel表格文件中)
    Android高手进阶教程(二)之Android Launcher抽屉类SlidingDrawer的使用!
    TabHost和TabWidget写出微信下面选项卡的界面
    android内存处理机制
  • 原文地址:https://www.cnblogs.com/tabcdt/p/2954973.html
Copyright © 2020-2023  润新知