图1:
1) ( 压入符号栈 2 ) 6压入数值栈
3) (与+比较优先级,认为(比+优先级低,则不满足计算条件,将+压入符号栈.
图2:
1) 将2 压入数值栈。
2) 将*与+比较优先级,算得+优先级低于*,则不满足计算条件,将*压入符号栈。
图3:
1) 将 5压入数植栈。 2) 将*与)比较优先级,得出*比)优先级要高。进行计算,将*出栈、5、2出栈,参与计算
图4:
1) 将 2*5 =10的结果压入数值栈。
2) (递归)比较 +与)优先级,得出+比)优先级要高。再进行计算,将+出栈、10、6出栈,参与计算。
图 5:
1) 将 6+10 =16的结果压入数值栈。
2) (递归)比较 )与(优先级,得出两者可以对消,将(符号出栈,与)对消,继续取下一个符号。
图6:
1) 将/入符号栈。
2)将4入数值栈。
3) 发现算式结束符,则进行计算, 将 /、4’、16出栈,参与计算。
图7:
1) 将计算结果压入数值栈。
成功了! 辛苦的计算工作终于干完了,看起来比人脑计算复杂多了:)
第二种算法
第二种方法,我们简单的提一下,在这里不作详细过程的叙述。第二种,就是使用树的方式,将一个算式组织成一定规律的树,之后,再进行遍历计算即得得到结果。还是以上面的算式作例子,最终形成的树的样式:(注意()这个符号要特殊处理)
图8:
使用树的深度遍历即可算出最终的结果。
程序实现
本文,给出使用栈处理四则运算的C#实现方法,如下:
CalUtility.csusing System;namespace Calculate{ /// summary /// CalUtility 的摘要说明。 /// 读算式辅助工具 /// /summary public class CalUtility { System.Text.StringBuilder StrB; private int iCurr=0; private int iCount=0; /// summary /// 构造方法 /// /summary public CalUtility(string calStr) { StrB = new System.Text.StringBuilder(calStr.Trim()); iCount = System.Text.Encoding.Default.GetByteCount(calStr.Trim()); } /// summary /// 取段,自动分析数值或计算符 /// /summary /// returns/returns public string getItem() { //结束了 if(iCurr==iCount) return ""; char ChTmp = StrB[iCurr]; bool b=IsNum(ChTmp); if(!b) { iCurr++; return ChTmp.ToString(); } string strTmp=""; while(IsNum(ChTmp)==b && iCurriCount) { ChTmp = StrB[iCurr]; if(IsNum(ChTmp)==b) strTmp +=ChTmp; else break; iCurr++; } return strTmp; } /// summary /// 是否是数字 /// /summary /// param name="c"内容/param /// returns/returns public bool IsNum(char c) { if((c=’0’ && c=’9’)|| c==’.’) { return true; } else { return false; } } /// summary /// 是否是数字 /// /summary /// param name="c"内容/param /// returns/returns public bool IsNum(string c) { if(c.Equals("")) return false; if((c[0]=’0’ && c[0]=’9’)|| c[0]==’.’) { return true; } else { return false; } } /// summary /// 比较str1和str2两个运算符的优先级,ture表示str1高于str2,false表示str1低于str2 /// /summary /// param name="str1"计算符1/param /// param name="str2"计算符2/param /// returns/returns public bool Compare(string str1,string str2) { return getPriority(str1)=getPriority(str2); } /// summary /// 取得计算符号的优先级 /// /summary /// param name="str"计算符/param /// returns/returns public int getPriority(string str) { if(str.Equals("")) { return -1; } if(str.Equals("(")) { return 0; } if(str.Equals("+")||str.Equals("-")) { return 1; } if(str.Equals("*")||str.Equals("/")) { return 2; } if(str.Equals(")")) { return 0; } return 0; } }}IOper.csusing System;namespace Calculate{ /// summary /// IOper 的摘要说明。 /// 计算符接口 /// /summary public interface IOper { /// summary /// 计算符计算接口计算方法 /// /summary /// param name="o1"参数1/param /// param name="o2"参数2/param /// returns/returns object Oper(object o1,object o2); }}Opers.csusing System;namespace Calculate{ /// summary /// Opers 的摘要说明。 /// 各类计算符的接口实现,加减乘除 /// /summary public class OperAdd:IOper { public OperAdd() { // // TODO: 在此处添加构造函数逻辑 // } #region IOper 成员 public object Oper(object o1, object o2) { Decimal d1 = Decimal.Parse(o1.ToString()); Decimal d2 = Decimal.Parse(o2.ToString()); return d1+d2; } #endregion}public class OperDec:IOper{ public OperDec() { // // TODO: 在此处添加构造函数逻辑 // } #region IOper 成员 public object Oper(object o1, object o2) { Decimal d1 = Decimal.Parse(o1.ToString()); Decimal d2 = Decimal.Parse(o2.ToString()); return d1-d2; } #endregion}public class OperRide:IOper{ public OperRide() { // // TODO: 在此处添加构造函数逻辑 // } #region IOper 成员 public object Oper(object o1, object o2) { Decimal d1 = Decimal.Parse(o1.ToString()); Decimal d2 = Decimal.Parse(o2.ToString()); return d1*d2; } #endregion}public class OperDiv:IOper{ public OperDiv() { // // TODO: 在此处添加构造函数逻辑 // } #region IOper 成员 public object Oper(object o1, object o2) { Decimal d1 = Decimal.Parse(o1.ToString()); Decimal d2 = Decimal.Parse(o2.ToString()); return d1/d2; } #endregion}}OperFactory.csusing System;namespace Calculate{ /// summary /// OperFactory 的摘要说明。 /// 计算符接口工厂 /// /summary public class OperFactory { public OperFactory() { } public IOper CreateOper(string Oper) { if(Oper.Equals("+")) { IOper p = new OperAdd(); return p; } if(Oper.Equals("-")) { IOper p = new OperDec(); return p; } if(Oper.Equals("*")) { IOper p = new OperRide(); return p; } if(Oper.Equals("/")) { IOper p = new OperDiv(); return p; } return null; } }}Calculate.csusing System;using System.Collections;namespace Calculate{ /// summary /// Calculate 的摘要说明。 /// 计算实现主类 /// /summary public class Calculate { /// summary /// 算术符栈 /// /summary private ArrayList HList; /// summary /// 数值栈 /// /summary public ArrayList Vlist; /// summary /// 读算试工具 /// /summary private CalUtility cu; /// summary /// 运算操作器工厂 /// /summary private OperFactory of; /// summary /// 构造方法 /// /summary /// param name="str"算式/param public Calculate(string str) { // // TODO: 在此处添加构造函数逻辑 // HList = new ArrayList(); Vlist = new ArrayList(); of = new OperFactory(); cu = new CalUtility(str); } /// summary /// 开始计算 /// /summary public object DoCal() { string strTmp=cu.getItem(); while(true) { if(cu.IsNum(strTmp)) { //如果是数值,则写入数据栈 Vlist.Add(strTmp); } else { //数值 Cal(strTmp); } if(strTmp.Equals("")) break; strTmp=cu.getItem(); } return Vlist[0]; } /// summary /// 计算 /// /summary /// param name="str"计算符/param private void Cal(string str) { //符号表为空,而且当前符号为"",则认为已经计算完毕 if(str.Equals("")&&HList.Count==0) return; if(HList.Count0) { //符号是否可以对消? if(HList[HList.Count-1].ToString().Equals("(") && str.Equals(")")) { HList.RemoveAt(HList.Count-1); if(HList.Count0) { str=HList[HList.Count-1].ToString(); HList.RemoveAt(HList.Count-1); Cal(str); } return; } //比较优先级 if(cu.Compare(HList[HList.Count-1].ToString(),str)) { //如果优先,则计算 IOper p = of.CreateOper(HList[HList.Count -1].ToString()); if(p!=null) { Vlist[Vlist.Count -2] = p.Oper(Vlist[Vlist.Count-2],Vlist[Vlist.Count-1]); HList.RemoveAt(HList.Count -1); Vlist.RemoveAt(Vlist.Count -1); Cal(str); } return; } if(!str.Equals("")) HList.Add(str); } else { if(!str.Equals("")) HList.Add(str); } } }}
后记
使用这种方法,我们可以完成更复杂的混合运算,比如说:可以支持函数运算的混合运算,更进一步,可以支持自定义函数的混合运算,最终可以将这种算法运用在自定义报表、工资处理等等应用领域,很希望有相关兴趣的朋友与我交流。