您好,欢迎访问三七文档
当前位置:首页 > 幼儿/小学教育 > 小学教育 > C#.NET逆波兰算法求解普通算式(支持自定义运算符)
先来一个例子:usingSystem;usingSystem.Collections.Generic;usingRPN;namespaceCSharp_Console{classProgram{publicstaticvoidMain(string[]args){varrpn=newReversePolishNotation();rpn.AddOperation(newPower('^',乘方,5));rpn.AddOperation(newE('e',科学记数法,5));varexpression=3^6+78*345+3-345/3e(-2)*(-9+3-5*7);try{Console.WriteLine(rpn.RpnExpression(expression));Console.WriteLine(rpn.Calculate(expression));}catch(Exceptionex){Console.WriteLine(ex.Message);}Console.ReadKey();}}//以下是定义拓展运算符,例子仅供参考classE:ReversePolishNotation.Operator{publicE(charsymbol,stringname,intpri):base(symbol,name,pri){}publicoverridedoubleCalc(doubleop1,doubleop2){returnop1*Math.Pow(10,op2);}}classPower:ReversePolishNotation.Operator{publicPower(charsymbol,stringname,intpri):base(symbol,name,pri){}publicoverridedoubleCalc(doubleop1,doubleop2){returnMath.Pow(op1,op2);}}}实现源代码:usingSystem;usingSystem.Collections.Generic;namespaceRPN{///summary///逆波兰表示法(后缀表示法)///remarks该类支持扩展运算符,你可以通过继承ReversePolishNotation.Operator来自定义自己的运算符,并通过ReversePolishNotation.AddOperation方法将实例化的运算符对象加入逆波兰表示法中。///Operator抽象类只有一个带参的构造函数Operator(char,string,int)。////remarks////summaryclassReversePolishNotation{Dictionarychar,InnerOperatoroperators;//记录操作符及其优先级///summary///查看该对象包含的所有运算符////summarypublicInnerOperator[]Operators{get{InnerOperator[]opts=newInnerOperator[operators.Count];inti=0;foreach(variteminoperators.Values){opts[i]=item;i++;}returnopts;}}///summary///用户可以添加自己的运算符////summary///paramname=opt实现运算符的自定义类/parampublicvoidAddOperation(Operatoropt){if(operators.ContainsKey(opt.Symbol))thrownewArgumentException(opt:指定的操作符符号已存在!);operators.Add(opt.Symbol,opt);}///summary///内置支持四则运算和括号调节优先级////summarypublicReversePolishNotation(){operators=newDictionarychar,InnerOperator();operators.Add(')',newRightBrace(')',右括号,1));operators.Add('(',newLeftBrace('(',左括号,2));operators.Add('+',newAdd('+',加,3));operators.Add('-',newMinus('-',减,3));operators.Add('*',newMutiply('*',乘,4));operators.Add('/',newDivide('/',除,4));}///summary///将中缀表达式转换为逆波兰表达式////summary///paramname=expression标准中缀表达式/param///returns标准逆波兰表达式/returnspublicstringRpnExpression(stringexpression){if(string.IsNullOrEmpty(expression))thrownewArgumentException(表达式不存在或者是空的!);//处理表达式字符串,使之完全合法化,否则报错expression=expression.Replace(,string.Empty);//清除所有空格if(expression.IndexOf(..)=0)//如果表达式中包含两个“..”,表示可能有数字输入有误thrownewArgumentException(表达式中某些数字可能不合法,或者表达式无法理解!);boolisDigit=false;//上一个字符是数字Stackcharopts=newStackchar();//运算符操作栈stringresult=string.Empty;charlastopt=char.MinValue;//标记上一操作字符,char.MinValue代表这是表达式的第一个字符for(inti=0;iexpression.Length;i++)//i值表示扫描到的数字在中缀表达式的位置{boolisNegative=false;//标记正负数字,用以处理负数if((lastopt==char.MinValue||lastopt=='(')&&expression[i]=='-')//如果表达式的第一个字符为‘-’或者是括号接下来的一个‘-’,则下面一个数字代表负数{isNegative=true;if(++i==expression.Length)//索引越界,跳出循环break;}if(char.IsDigit(expression[i]))//如果是数字,就分析到底{stringstrNum=string.Empty;//创建一个数字字符串do{strNum+=expression[i].ToString();//将字符加入字符串//处理完毕,下移一位if(++i==expression.Length)//索引越界,跳出循环break;if(char.IsDigit(expression[i])||expression[i]=='.')//如果是数字或者点号就还算数字isDigit=true;elseisDigit=false;}while(isDigit);//数字生成完毕//直接输出数字if(isNegative)//根据正负数输出不同的结果result+=-+strNum+;elseresult+=strNum+;}//数字分析完毕,并已经转到下一字符,且这一字符必然为操作符if(iexpression.Length)//判断索引是否越界{if(!operators.ContainsKey(expression[i]))thrownewArgumentException(算式中含有不支持的运算符!);//支持该运算符while(opts.Count0&&(operators[opts.Peek()].Pri=operators[expression[i]].Pri)&&expression[i]!='(')//当前操作符优先级低于栈顶元素;当出现左括号时,其优先级最高,直接压入栈{result+=opts.Pop().ToString()+;//栈顶运算符出栈并输出到结果字符串}opts.Push(expression[i]);//将当前运算符入栈lastopt=expression[i];//记录当前操作符}}//字符串处理完毕,开始扫尾工作while(opts.Count0)//将栈中的运算符退栈并输出到结果字符串{result+=opts.Pop().ToString()+;}result=result.Replace((,string.Empty).Replace(),string.Empty).TrimEnd();//去除字符串中的括号,和最后的一个空格if(this.isRPN(result))returnresult;elsethrownewArgumentException(表达式不能被理解!);}///summary///判断输出的表达式是否是一个合格的逆波兰表达式////summary///paramname=rpn要分析的逆波兰表达式/paramboolisRPN(stringrpn){StackstringrpnStack=newStackstring();for(inti=0;irpn.Length;i++)//从头至尾分析逆波兰表达式{stringstrTemp=string.Empty;while(irpn.Length&&rpn[i]!='')//当遇到空格或者到达字符串结尾就结束循环{strTemp+=rpn[i].ToString();i++;}if(strTemp.Length==1&&operators.ContainsKey(strTemp[0]))//说明是个操作符{if(rpnStack.Count2)//不够退两次栈,逆波兰表达式有误returnfalse;//退栈一次rpnStack.Pop();}else//操作数入栈{rpnStack.Push(strTemp);}}if(rpnStack.Count==1&&!operators.ContainsKey(rpnStack.Pop()[0]))//栈剩余一个结果且不是操作符,则逆波兰表达式无误returntrue;elsereturnfalse;}///summary///输入中缀表达式返回算式的值////summary///paramname=expression中缀表达式/parampublicdoubleCalculate(stringexpression){stringrpn=this.RpnExpression(expression);//这是经过验证的逆波兰表达式,在本次计算中,无需进行多余的判断操作StackstringrpnStack=newStackstring();for(inti=0;irpn.Length;i++)//从头至尾分析逆波兰表达式{stringstrTemp=string.Empty;while(irpn.Length&&rpn[i]!='')//当遇到空格或者到达字符串结尾就结束循环{strTemp+=rpn[i].ToString();i++;}if(strTemp.Length==1&&operators.ContainsKey(strTemp[0]))//说明是个操作符{varop2=double.Parse(rpnStack.Pop());varop1=double.Parse(rpnStack.Pop());rpnStack
本文标题:C#.NET逆波兰算法求解普通算式(支持自定义运算符)
链接地址:https://www.777doc.com/doc-4427921 .html