c#栈应用——实现四则运算

前言:四则运算,大家都不陌生,在上小学的时候,数学中学到过的知识,那么如何在程序中实现呢?下面,我们就用程序来实现9+(3-2)*(5-3)/4*3,这个算式的值。计算的时候,有一个规则”先乘除,后加减,从左到右,先括号内后括号外“。

其优先级就是 加减<乘除<括号

这个算式,我们可以很轻松的计算出它的值等于10.5。这是我们常用的四则表达式,又叫做中缀表达式。这种计算的复杂之处在与乘除在加减之后,并且还有括号,放在程序里的判断,就复杂了,那么如何简化呢?伟大的科学家想到了好的处理办法,

一、逆波兰(Reverse Polish Notation,RPN):一种不需要括号的后缀表达法,我们也称之为逆波兰。

上面的四则运算表达式,转换未后缀表达法之后,变为 9 3 2 - * 5 3 - 4 / 3 * +,叫后缀的原因所有的符号都是在要运算数字的后面出现。

如何实现由中缀表达式转化未后缀表达式呢?

规则:依次从左向右遍历表达式,若是数字加入到集合;若是符号,则需要判断其与栈顶符号的优先级,如果当前元素是右括号或优先级较低的符号,则栈顶的元素一次出栈并输出,并将当前符号进栈;如果当前元素和栈顶的元素优先级相同,将栈顶的同级元素依次出栈。

实现代码:

string str = "9+(3-2)*(5-3)/4*3";
string cz = ")+-";   //需要出栈的操作
string rz = "(*/";   //入栈的符号
string hig = "*/";   //优先级高的
string zkh = "(";    //左括号
string ykh = ")";    //右括号
Stack stack = new Stack();
int lj = str.Length - 1;
ArrayList list = new ArrayList();
//从左到右遍历中缀表达式的每个数字和符号,
for (int i = 0; i < str.Length; i++)
{
     string item = str.Substring(i, 1);
     //1、若是数字输出,即成为后缀表达式的一部分;
     if (digital.Contains(item))
     {
          Console.Write($"{item}\t");
          list.Add(item);
     }
     else
     {
          //若是符号
          if (rz.Contains(item) || stack.Count == 0)
          {
               if (stack.Count > 0)
               {
                   string chr = (string)stack.Pop();
                   if (hig.Contains(chr))
                   {
                        list.Add(chr);
                        Console.Write($"{chr}\t");
                   }
                   else
                   {
                        stack.Push(chr);
                    }
                }
                stack.Push(item);
            }
            else
            {
                //优先级低与栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出
                if (ykh.Contains(item))
                {
                    while (stack.Count > 0)
                    {
                        string zk = (string)stack.Pop();
                        if (zkh.Contains(zk))
                        {
                             break;
                        }
                        list.Add(zk);
                        Console.Write($"{zk}\t");
                     }
                     continue;
                 }
                 if (cz.Contains(item))
                 {
                     string chr = (string)stack.Pop();
                     if (hig.Contains(chr))
                     {
                         list.Add(chr);
                         Console.Write($"{chr}\t");
                         while (stack.Count > 0)
                         {
                             string ab = (string)stack.Pop();
                             list.Add(ab);
                             Console.Write($"{ab}\t");
                          }
                      }
                      else
                     {
                           stack.Push(chr);
                      }
                     stack.Push(item);
                     continue;
                  }
                        stack.Push(item);
           }
          }
          if (lj == i)
          {
              while (stack.Count > 0)
              {
                   string ab = (string)stack.Pop();
                   list.Add(ab);
                        Console.Write($"{ab}\t");
               }
            }
     }
     Console.WriteLine();
     for(var i= 0; i < list.Count; i++)
     {
         string a = list[i].ToString();
         Console.Write($"{a} \t");
     }

二、由上面计算得到后缀表达式,那么如何使用栈来计算这个表达式呢?

计算规则:依次遍历后缀表达式,如果是数字,则入栈,如果是符号,则将栈顶的两个元素出栈,进行计算,计算完成之后,将结果入栈。

代码如下:

string digital = "0123456789";
Stack calcStack = new Stack();
foreach(var item in list)
{
      //如果是数字,入栈
      if (digital.Contains(item.ToString()))
       {
          calcStack.Push(item);
       }
       else
       {
           //如果是符号,则把栈顶的两个数字出栈,进行计算,入栈。
           string clfh = item.ToString();
           double hz1, hz2;
           double.TryParse(calcStack.Pop().ToString(), out hz2);
           double.TryParse(calcStack.Pop().ToString(), out hz1);
           double result = GetResult(hz1, hz2, clfh);
           calcStack.Push(result);
      }
}
Console.WriteLine();
Console.WriteLine();
while (calcStack.Count > 0)
{
    Console.WriteLine($"{str} = {calcStack.Pop()}");
}
private static double GetResult (double ca1, double ca2,string fh)
{
    if(fh=="+")
        return ca1 + ca2;
    else if(fh=="-")
        return ca1 - ca2;
    else if(fh== "*")
        return ca1 * ca2;
    else
        return ca1 / ca2;
}

备注:其中逆波兰解释,来自《大话数据结构》一书。

PS:当前代码计算小于10的四则运算。

欢迎大家批评指正,小可不胜感激。

你可能感兴趣的:(c#,开发语言)