您的位置:首页 > 编程语言 > C#

C# 中实现表达式计算

2011-10-05 13:25 351 查看
提要:

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遍历,寻找运算符。

期待找到更好的算法。

 //按钮"="的响应代码
   protectedvoidButtonEqual_Click(objectsender,EventArgse)
   {
       
       intsi=0;
       ints=1;//s=0时:上一个元素是数字。s=1时,上一个是符号
   
       Stringres=TextBoxResult.Text;
       char[]str=TextBoxResult.Text.ToCharArray();
       string[]resSplit=res.Split(newchar[]{'+','-','*','/','(',')'});
 
       try
       {
           for(inti=0;i<str.Length;i++)
           {
               nodetmp=newnode();//临时节点
               if((str[i]==46||(str[i]-48<=9&&0<=str[i]-48))&&s==1)//新加入的元素是数值
               {
                   tmp.sign=false;
                   while(true)
                   {
                       if(resSplit[si]!="")
                       {
                           tmp.num=Convert.ToDouble(resSplit[si]);
                           break;
                       }
                       elsesi++;
                   }
                    
                   Q1.Enqueue(tmp);
                   Label1.Text=Label1.Text+tmp.num;//测试
                   s=0;
                   si++;
               }
               elseif((str[i]==46||(str[i]-48<=9&&0<=str[i]-48))&&s==0)//新加入的元素是数字,但前面元素也是
               {
                   continue;
               }
               else
               {
                   tmp.sign=true;
                   tmp.symbol=str[i];
                   if(tmp.symbol=='*'||tmp.symbol=='/')tmp.priority=2;
                   elseif(tmp.symbol=='+'||tmp.symbol=='-')tmp.priority=1;
                   s=1;
                   Q1.Enqueue(tmp);
                   Label1.Text=Label1.Text+tmp.symbol;//测试
               }
           }
         
           change();
          doubler=calculate();
           if(err==false)Label1.Text=Label1.Text+"="+r+"<br/>";
           else          Label1.Text=Label1.Text+"error!<br/>";//测试
       }
       catch(Exceptionew)
       {
           Label1.Text=Label1.Text+"error!<br/>";//测试
       }
   }

三中缀-后缀

 publicvoidchange()//2)将中缀表达式转换成后缀表达式;
   {
       while(Q1.Count!=0)
       {
           if(Q1.Peek().sign==false)//是数字,放入队列
           {
               Q2.Enqueue(Q1.Peek());
           }
           else
           {
               if(Q1.Peek().symbol=='(')//当输入的是左括号,则把它压栈。
                   Sc.Push(Q1.Peek());
               elseif(Q1.Peek().symbol==')')//当输入的是右括号,
               {
                   if(Sc.Count()==0)
                   {
                       err=true;
                       break;
                   }
                   else
                   {
                       while(Sc.Peek().symbol!='(')
                       {
                           Q2.Enqueue(Sc.Peek());
                           Sc.Pop();
                           if(Sc.Count()==0)
                           {
                               err=true;
                               break;
                           }
                       }
                       if(Sc.Count()!=0) Sc.Pop();
                   }
               }
               else
               {
                   while(Sc.Count()!=0&&Q1.Peek().symbol!='('&&Q1.Peek().priority<=Sc.Peek().priority)
                   {
                       Q2.Enqueue(Sc.Peek());
                       Sc.Pop();
                   }
                   Sc.Push(Q1.Peek());
               }
           }
           Q1.Dequeue();
       }
       while(Sc.Count()!=0)
       {
           if(Sc.Peek().symbol=='(')
           {
               err=true;
               break;
           }
           Q2.Enqueue(Sc.Peek());
           Sc.Pop();
       }

   }

四后缀求解
publicdoublecalculate()
{
Stack<node>stmp=newStack<node>();
doublenum1=0;
doublenum2=0;
nodetmp=newnode();
while(Q2.Count!=0)
{
if(Q2.Peek().sign==false)
{
stmp.Push(Q2.Peek());
}
elseif(Q2.Peek().sign==true)
{
num2=stmp.Peek().num;
stmp.Pop();
num1=stmp.Peek().num;
stmp.Pop();
if(Q2.Peek().symbol=='+')
{
tmp.num=num1+num2;
tmp.priority=1;
tmp.sign=false;
}
elseif(Q2.Peek().symbol=='-')
{
tmp.num=num1-num2;
tmp.priority=1;
tmp.sign=false;
}
elseif(Q2.Peek().symbol=='*')
{
tmp.num=num1*num2;
tmp.priority=2;
tmp.sign=false;
}
elseif(Q2.Peek().symbol=='/')
{
tmp.num=num1/num2;
tmp.priority=2;
tmp.sign=false;
}
stmp.Push(tmp);
}
Q2.Dequeue();
}

if(stmp.Count()!=1)err=true;

returnstmp.Peek().num;

}


五、不足:

1随便写了点,代码还很不规范

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

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

4不支持负数,如-6计算时会出错,需写成:(0-6)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息