javascript - 如何修改调车场算法以使其接受一元运算符?

标签 javascript algorithm shunting-yard

我一直致力于在类里面用 JavaScript 实现调车场算法。

这是我目前的工作:

var userInput = prompt("Enter in a mathematical expression:");
var postFix = InfixToPostfix(userInput);
var result = EvaluateExpression(postFix);

document.write("Infix: " + userInput + "<br/>");
document.write("Postfix (RPN): " + postFix + "<br/>");
document.write("Result: " + result + "<br/>");


function EvaluateExpression(expression)
{
    var tokens = expression.split(/([0-9]+|[*+-\/()])/);
    var evalStack = [];

    while (tokens.length != 0)
    {
        var currentToken = tokens.shift();

        if (isNumber(currentToken))
        {
            evalStack.push(currentToken);
        }
        else if (isOperator(currentToken))
        {
            var operand1 = evalStack.pop();
            var operand2 = evalStack.pop();

            var result = PerformOperation(parseInt(operand1), parseInt(operand2), currentToken);
            evalStack.push(result);
        }
    }
    return evalStack.pop();
}

function PerformOperation(operand1, operand2, operator)
{
    switch(operator)
    {
        case '+': 
            return operand1 + operand2;
        case '-':
            return operand1 - operand2;
        case '*':
            return operand1 * operand2;
        case '/':
            return operand1 / operand2;
        default:
            return;
    }

}

function InfixToPostfix(expression)
{
    var tokens = expression.split(/([0-9]+|[*+-\/()])/);
    var outputQueue = [];
    var operatorStack = [];

    while (tokens.length != 0)
    {
        var currentToken = tokens.shift();

        if (isNumber(currentToken)) 
        {
            outputQueue.push(currentToken);
        }
        else if (isOperator(currentToken)) 
        {
            while ((getAssociativity(currentToken) == 'left' && 
                    getPrecedence(currentToken) <= getPrecedence(operatorStack[operatorStack.length-1])) ||
                   (getAssociativity(currentToken) == 'right' && 
                    getPrecedence(currentToken) < getPrecedence(operatorStack[operatorStack.length-1]))) 
            {
                outputQueue.push(operatorStack.pop())
            }

            operatorStack.push(currentToken);

        }
        else if (currentToken == '(')
        {
                operatorStack.push(currentToken);
        }
        else if (currentToken == ')')
        {
            while (operatorStack[operatorStack.length-1] != '(')
            {
                if (operatorStack.length == 0)
                    throw("Parenthesis balancing error! Shame on you!");

                outputQueue.push(operatorStack.pop());
            }   
            operatorStack.pop();        
        }   
    }  

    while (operatorStack.length != 0)
    {
        if (!operatorStack[operatorStack.length-1].match(/([()])/))
            outputQueue.push(operatorStack.pop());
        else
            throw("Parenthesis balancing error! Shame on you!");         
    }

    return outputQueue.join(" ");
}    


function isOperator(token)
{
    if (!token.match(/([*+-\/])/))
        return false;
    else 
        return true;
}


function isNumber(token)
{
    if (!token.match(/([0-9]+)/))
        return false;
    else
        return true;
}


function getPrecedence(token)
{
    switch (token)
    {
        case '^':
            return 9; 
        case '*':           
        case '/':
        case '%':
            return 8;
        case '+':
        case '-':
            return 6;
        default: 
            return -1;
    }
}

function getAssociativity(token)
{
    switch(token)
    {
        case '+':
        case '-':
        case '*':
        case '/':
            return 'left';
        case '^':
            return 'right';
    }

}

到目前为止一切正常。如果我给它:

((5+3) * 8)

它会输出:

Infix: ((5+3) * 8)
Postfix (RPN): 5 3 + 8 *
Result: 64

但是,我正在努力实现一元运算符,所以我可以做类似的事情:

((-5+3) * 8)

什么是实现一元运算符(否定等)的最佳方式?另外,有人对处理 float 有什么建议吗?

最后一件事,如果有人看到我在 JavaScript 中做任何奇怪的事情,请告诉我。这是我的第一个 JavaScript 程序,我还不习惯。

最佳答案

最简单的方法是让 isNumber 匹配 /-?[0-9]+(\.[0-9]+)?/,同时处理这两个 float 和负数。

如果你真的需要处理一元运算符(比如,括号表达式的一元取反),那么你必须:

  • 使它们右结合。
  • 使它们的优先级高于任何中缀运算符。
  • EvaluateExpression 中分别处理它们(制作一个单独的 PerformUnaryExpression 函数,它只接受一个操作数)。
  • 通过跟踪某种状态来区分 InfixToPostfix 中的一元减号和二元减号。看看这个 Python example'-' 是如何变成 '-u' 的.

我在 another SO question 上写了关于处理一元减号的更详尽的解释.

关于javascript - 如何修改调车场算法以使其接受一元运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1593080/

相关文章:

unsigned long long int 值中的 C++ 奇怪跳转

javascript - 使用 ng-repeat、ng-model 和复选框获取数组中的位置

java - 在调车场保留括号

algorithm - 必须实现调车场算法,需要帮助理解它

javascript - 如何在 onMouseOver 和 onMouseOut 中定义函数

javascript - 无法在 Firefox 中调试 Typescript(源)文件

javascript - 如何使用 jsreport 和 jsreport Chrome Pdf 渲染 1k pdf 文件?

algorithm - 这个三重嵌套循环的大 O?

compiler-construction - 使用逆波兰表示法 (RPN) 进行算术表达式评估

javascript - 如何更轻松地使用随机 href 设置 anchor ?