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

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

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

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

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

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

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

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

实现代码:

/// <summary>
/// 利用正则表达式,分别获取数字和符号,然后组装到集合中。
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<string> GetOpList(string str)
{
     string pattern = (@"\d+");
     Regex validate = new Regex(pattern);
     MatchCollection col = validate.Matches(str);

            //string patternFh = (@"(\+|\-|\*|\/|\(|\))");
     string patternFh = @"\D+";
     Regex validateFh = new Regex(patternFh);
     MatchCollection colFh = validateFh.Matches(str);

     List<string> list = new List<string>();
     int nFhIndex = 0;
     for (int i = 0; i < col.Count; i++)
     {
         Match mD = col[i];
         list.Add(mD.Value);
         if (nFhIndex < colFh.Count)
         {
             Match mf = colFh[nFhIndex];
             string strTemp = mf.Value;
             int nTempLen = strTemp.Length;
             for(int j = 0; j < nTempLen; j++)
             {
                 list.Add(strTemp.Substring(j, 1));
             }
             nFhIndex++;
        }
     }
     return list;
}


/// <summary>
/// 当前只限定加减乘除小括号
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private List<string> GetNextPrevRegex(string str)
{
    string hig = "*/";   //优先级高的
    string zkh = "(";    //左括号
    string ykh = ")";    //右括号
    Stack stack = new Stack();

    List<string> list = new List<string>();
    List<string> listOp = GetOpList(str);
    //从左到右遍历中缀表达式的每个数字和符号,
    for (int i = 0; i < listOp.Count; i++)
    {
        string item = listOp[i];
        //1、若是数字输出,即成为后缀表达式的一部分;
        if (IsNumeric(item))
        {
            list.Add(item);
            continue;
        }
        if (stack.Count == 0 || zkh == item)
        {
            stack.Push(item);
            continue;
        }
        //这里限定了默认条件,是必须+-*/),才到这里。
        while (stack.Count > 0)
        {
            string ab = stack.Peek().ToString();
            if (ykh == item)
            {
                if (zkh == ab)
                {
                            stack.Pop();  //将左括号出栈
                            break;
                }
                list.Add(stack.Pop().ToString());
                continue;
           }
           if (!hig.Contains(ab))
                 break;
           list.Add(stack.Pop().ToString());
        }
        if (!ykh.Contains(item))
             stack.Push(item);
     }
     while (stack.Count > 0)
     {
        list.Add(stack.Pop().ToString());
     }
     return list;
}

private bool IsNumeric(string token)
{
     bool blag = true;
     string pattern = (@"^\d+$");
     Regex validate = new Regex(pattern);
     if (!validate.IsMatch(token))
     {
         blag = false;
     }
     return blag;
}

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

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

代码如下:

public double GetResult(string calc)
{
     List<string> list = GetNextPrevRegex(calc);
     Stack calcStack = new Stack();
     foreach (var item in list)
     {
          string temp = item.ToString();
          //如果是数字,入栈
          if (IsNumeric(temp))
          {
              calcStack.Push(temp);
              continue;
          }
                //如果是符号,则把栈顶的两个数字出栈,进行计算,入栈。
          double.TryParse(calcStack.Pop().ToString(), out double hz2);
          double.TryParse(calcStack.Pop().ToString(), out double hz1);
          double result = GetResultByFh(hz1, hz2, temp);
          calcStack.Push(result);
    }
    string sResult = calcStack.Pop().ToString();
    double.TryParse(sResult, out double calcresult);
    return calcresult;
}
private double GetResultByFh(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;
}

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fervour

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值