【问题标题】:Math Expression Evaluator Gone Wrong数学表达式评估器出错了
【发布时间】:2013-03-12 05:39:11
【问题描述】:

大家好,

我已经开始使用 Dijkstra 两个堆栈算法制作这个数学表达式评估器,我想我已经仔细应用了所有规则,但问题是它可以正确评估一些表达式和一些错误:/

//I made it in a Console project
 static void Main(string[] args)
        {
        string expression = "2*3+232+34*45/3-4*45+3";
        //remove all whitespaces
        expression = expression.Trim();

        //two stacks needed
        var values = new Stack<double>();
        var operators = new Stack<char>();
    Dictionary<char, OperatorInfo> operatorList = new Dictionary<char, OperatorInfo> 
    {
        {'+',new OperatorInfo('+',"Add",2,OperatorFixity.Left)},
        {'-',new OperatorInfo('-',"Minus",2,OperatorFixity.Left)},
        {'/',new OperatorInfo('/',"Divide",3,OperatorFixity.Left)},
        {'*',new OperatorInfo('*',"Multiply",3,OperatorFixity.Left)},
        {'^',new OperatorInfo('^',"Caret",4,OperatorFixity.Right)}
    };

    for (int i = 0; i < expression.Length; i++)
    {
        if (expression[i].Equals('('))
            continue;//ignore it 
        else if (IsNumber(expression[i].ToString()))//if its a number
        {
            //extract number
            string[] getNumberNCount =
                getNumberAndCount(expression.Substring(i)).Split(',');
            double val = double.Parse(getNumberNCount[0]);
            int count = int.Parse(getNumberNCount[1]);
            values.Push(val);
            i += count;
        }
        else if (IsOperator(expression[i]))
        {
            //Maintain precedence on stack
            if (operators.Count > 0)
            {
               CheckPrecedence(expression[i], ref values, ref operators, operatorList);
            }
            else
                operators.Push(expression[i]);//runs first time only
        }
    }

    //now most precedence is solved
    while (operators.Count != 0)
    {
        var LastOperand = values.Pop();
        var PrevOperand = values.Pop();
        var lastOperator = operators.Pop();
        values.Push(calculateExpression(lastOperator, LastOperand, PrevOperand));
    }
    Console.WriteLine("Input Expression is: " + expression);
    Console.WriteLine("Result is: " + values.Pop());
    Console.ReadLine();
}

//it checks for precedence of operators before push
//that's the basic logic for calculation
  private static void CheckPrecedence(char currentOp, ref Stack<double> values, ref Stack<char> operators, Dictionary<char, OperatorInfo> operatorList)
        {
            char lastStackOp = operators.Peek();
            //if same precedence of both Op are same
            //OR lastOp > than CurrentOp
            if ((operatorList[lastStackOp].Precedence == operatorList[currentOp].Precedence) ||
                    (operatorList[lastStackOp].Precedence > operatorList[currentOp].Precedence))
            {
                var TopMostOperand = values.Pop();
                var PrevOperand = values.Pop();
                var TopMostOperator = operators.Pop();
                values.Push(calculateExpression(TopMostOperator, TopMostOperand, PrevOperand));
                operators.Push(currentOp);
            }
            else
            {
                operators.Push(currentOp);
            }
        }

//extracts out number from string
        public static string getNumberAndCount(string numberStr)
        {
            var number = "";
            int count = 0;
            if (numberStr.Length >= 1)
            {
                while (IsNumber(numberStr[count].ToString()))
                {
                    number += numberStr[count];
                    if (numberStr.Length == 1)
                        break;
                    count++;
                }
            }
            return number + "," + (count == 0 ? count : count - 1);
        }

问题:
1)为什么当我正确应用规则时它仍然不起作用(我知道我在某处犯了错误)
2) 添加括号支持怎么办?

P.S:我必须为应用程序制作这个..

【问题讨论】:

  • @BenVoigt 谢谢你,我浏览过 Wiki,其他随机文章 + SO 帖子,这就是我现在在这里的原因
  • @BenVoigt 我发现 wiki 文章令人困惑
  • 好吧,在寻找解释和示例代码时,知道算法的名称是“调车场”(多于)成功。
  • @BenVoigt 谢谢你,如果你告诉我算法名称,我已经知道了,我在某种程度上搞砸了算法实现:-/,这就是我现在面临的问题。

标签: c# algorithm parsing math evaluation


【解决方案1】:

尝试更改此方法:

private static void CheckPrecedence(char currentOp, ref Stack<double> values, ref Stack<char> operators,
                                        Dictionary<char, int> operatorList)
    {
        char lastStackOp = operators.Peek();
        //if same precedence of both Op are same
        //OR lastOp > than CurrentOp
        while (((operatorList[lastStackOp] == operatorList[currentOp]) ||
            (operatorList[lastStackOp] > operatorList[currentOp])))
        {
            var TopMostOperand = values.Pop();
            var PrevOperand = values.Pop();
            var TopMostOperator = operators.Pop();
            values.Push(calculateExpression(TopMostOperator, TopMostOperand, PrevOperand));

            if (operators.Count == 0)
                break;

            lastStackOp = operators.Peek();
        }
        operators.Push(currentOp);

    }

问题是,如果您最终评估堆栈中的运算符,因为它具有比当前操作更高的优先级,您必须检查堆栈的新头部是否具有比当前操作更高或相等的优先级也是。我已将 if 语句替换为 while 循环以继续检查,直到不再满足条件为止。

我会尝试让括号工作,并会在几分钟后回来查看:)

编辑(用于括号): 括号被视为特殊字符,仅在关闭后才被评估。要让它们正常工作,请将以下 2 个值添加到 operatorlist:

    {'*',new OperatorInfo('(',"OpenBracket",5,OperatorFixity.Left)},
    {'^',new OperatorInfo(')',"CloseBracket",5,OperatorFixity.Left)}

然后改变这个:

else if (IsOperator(expression[i]))
{
    //Maintain precedence on stack
    if (operators.Count > 0)
    {
       CheckPrecedence(expression[i], ref values, ref operators, operatorList);
    }
    else
        operators.Push(expression[i]);//runs first time only
}

到这里:

else if (IsOperator(expression[i]))
{
    //Maintain precedence on stack
    if (operators.Count > 0 && expression[i] != '(' && expression[i] != ')')
    {
        CheckPrecedence(expression[i], ref values, ref operators, operatorList);
    }
    else if (expression[i] == ')')
    {
        while (operators.Peek() != '(')
        {
            var lastOperator = operators.Pop();
            var LastOperand = values.Pop();
            var PrevOperand = values.Pop();
            values.Push(calculateExpression(lastOperator, LastOperand, PrevOperand));
        }
        operators.Pop();
    }
    else
        operators.Push(expression[i]);
    }

【讨论】:

  • 感谢修复,除括号外,所有基本运算符均正常工作,+1 帮助
  • 括号会发生什么?以上适用于我的机器:P
  • 我用这个表达式来检查括号评估 ((4*58)-((89+85*3)/200)/100) 结果是 143.01275 但正确答案是 231.9828
  • 奇怪。我的结果是 231.9828
  • 由于某种原因,您的评估好像没有括号。确保括号在具有高优先级值的运算符列表中
猜你喜欢
  • 1970-01-01
  • 2010-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-30
相关资源
最近更新 更多