自己写的一个用栈方法来计算的数学表达式

Posted on 2008-06-01 16:00  Leon0812  阅读(736)  评论(0)    收藏  举报
思路如下:
用栈计算表达式的方法原理及步骤:
建立两个栈,一个是数据栈,一个是计算符号栈,以(6+2*5)/4为例


1 优先级
符号之间的优先级如下:
"(" , ")"        -1
"+" , "-"       0
"*" , "/"        1
数值越大,则越优先,同级别的比较时 先出现的优先。

2 将"(",")"设为特殊运算符,即单目运算,两邻两个运算符则可对消。

3 计算条件
(1) 当前运算符不等于""(特殊结束符)
(2) 运算符栈里的运行算个数>=1时
(3) 出栈口的运算符优先级高于将要入栈的运算符时或者两者可对消时。

4 计算时,则将符号出栈参与计算,数值栈的出栈口前两位元素出栈参与计算,
计算结果值向数值栈压栈,并进行递归此操作。具体步骤如下:

(1) "(" 压入符号栈
(2) "6"压入数值栈
(3) "("与"+"比较优先级,认为"("比"+"优先级低,则不满足计算条件,将"+"压入符号栈.
(4) 将"2" 压入数值栈。
(5) 将"*"与"+"比较优先级,算得"+"优先级低于"*",则不满足计算条件,将"*"压入符号栈。
(6) 将 "5"压入数植栈。
(7) 将"*"与")"比较优先级,得出"*"比")"优先级要高。进行计算,将"*"出栈、"5"、"2"出栈,参与计算
(8) 将 2*5 =10的结果压入数值栈。
(9) (递归)比较 "+"与")"优先级,得出"+"比")"优先级要高。再进行计算,将"+"出栈、"10"、"6"出栈,参与计算。
(10) 将 6+10 =16的结果压入数值栈。
(11) (递归)比较 ")"与"("优先级,得出两者可以对消,将"("符号出栈,与")"对消,继续取下一个符号。
(12) 将"/"入符号栈。
(13) 将"4"入数值栈。
(14) 发现""算式结束符,则进行计算, 将 "/"、"4’、"16"出栈,参与计算。
(15) 将计算结果压入数值栈。
源码如下:
  1using System;
  2using System.Data;
  3using System.Configuration;
  4using System.Collections;
  5using System.Web;
  6using System.Web.Security;
  7using System.Web.UI;
  8using System.Web.UI.WebControls;
  9using System.Web.UI.WebControls.WebParts;
 10using System.Web.UI.HtmlControls;
 11
 12public partial class Default2 : System.Web.UI.Page
 13{
 14    //返回值
 15    double result = 0.00;
 16    //数值栈
 17    Stack stNum = new Stack();
 18    //符号栈
 19    Stack stOptr = new Stack();
 20
 21    //ArrayList里对象转为字符串方便判断
 22    string para;
 23    //数值栈中倒数第二个值
 24    string tempNum1;
 25    //数值栈中倒数第一个值
 26    string tempNum2;
 27    //符号栈中倒数第一个值
 28    string tempOptr;
 29    //优先级对比返回值;
 30    string cmpStr = "";
 31    //临时计算结果
 32    double tempResult = 0.00;
 33
 34    //按钮事件
 35    protected void btnCal_Click(object sender, EventArgs e)
 36    {
 37        ArrayList al = GetExpression(this.tbxExpression.Text.Trim());
 38        this.lbResult.Text = Calculate(al).ToString();
 39    }

 40
 41    /// <summary>
 42    /// 计算过程
 43    /// </summary>
 44    /// <param name="al">array表达式</param>
 45    /// <returns></returns>

 46    public double Calculate(ArrayList al)
 47    {
 48
 49        for (int i = 0; i < al.Count; i++)
 50        
 51            /* 要运算必须符号以下条件:
 52             * (1)数值栈有两个或两个以上的值
 53             * (2)符号栈中有一个或一个以上的值
 54             * (3)并且当前值是符号或者是ArrayList最后一项(后者情况放最后处理)
 55             * 具体步骤:
 56             * step1:如果当前值是符号,对比优先级别后可以判断是否计算,如可以计算跳至step3
 57             * step2:如果当前值是ArrayList最后一项,则跳至step3
 58             * step3:提取数值栈中最后两个值,符号栈中最后一个值进行计算(当然符号栈中运算符不能为"("号或者为")"号) */

 59            
 60            para = al[i].ToString();
 61            //如果是最后一位且为数字,则压入栈
 62            if (i == al.Count - 1 && !IsOptr(para))
 63            {
 64                stNum.Push(para);
 65            }

 66
 67            if (stNum.Count > 1 && stOptr.Count > 0)
 68            {
 69                符合条件进行计算
106            }

107            else
108            {
109                插入栈
120            }

121
122        }

123
124        result = double.Parse(stNum.Peek().ToString());
125        return result;
126    }

127
128    //递归计算
129    private void CircleCal()
130    {
131        if (stNum.Count > 1 && stOptr.Count > 0 && IsOptr(para))
132        {
133            //弹出计算
134            tempNum2 = stNum.Pop().ToString();
135            tempNum1 = stNum.Pop().ToString();
136            tempOptr = stOptr.Pop().ToString();
137
138            //对比优先级
139            cmpStr = CmpPRI(tempOptr, para);
140            if (!string.IsNullOrEmpty(cmpStr))
141            {
142                //如果是等号说明是:"("号或")"号,单独处理而不计算
143                if ("=" == cmpStr)
144                {
145                    //如果是匹配的一对左右括号,单目计算,符号对消掉 
146                    if (tempOptr == "(" && para == ")")
147                    {
148                        //不符合重新push回去,只把数值push回去,符号对消掉
149                        stNum.Push(tempNum1);
150                        stNum.Push(tempNum2);
151                        para = "#";
152                        CircleCal();
153                    }

154                    else
155                    {
156                        //不符合重新push回去
157                        stNum.Push(tempNum1);
158                        stNum.Push(tempNum2);
159                        stOptr.Push(tempOptr);
160                        //push入符号
161                        stOptr.Push(para);
162                        para = "#";
163                        CircleCal();
164                    }

165                }

166                else if (">" == cmpStr)
167                {
168                    //真正符合条件进行计算
169                    tempResult = CalNums(double.Parse(tempNum1), double.Parse(tempNum2), tempOptr);
170                    //结果要push回数值栈去
171                    stNum.Push(tempResult);
172                    //递归计算
173                    CircleCal();
174                }

175                else
176                {
177                    //不符合重新push回去
178                    stNum.Push(tempNum1);
179                    stNum.Push(tempNum2);
180                    stOptr.Push(tempOptr);
181                    //push入符号
182                    stOptr.Push(para);
183                    para = "";
184                }

185            }

186        }

187    }

188
189    函数
380
381}

382

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3