具有功能支持的Infix到Postfix

时间:2012-07-29 09:36:29

标签: c++ algorithm function infix-notation postfix-notation

有许多算法可以在整个网络上将中缀转换为后缀。但我的问题是如何使其支持功能?例如sin(x + y)* z。

我会很感激代码。

5 个答案:

答案 0 :(得分:3)

这很简单:它也适用于函数,你使用的常规运算符(如+, - ,*)也是函数。你的问题是,你认为“功能”(如罪)不是在中缀,而是在前缀中。

回到你的问题:只需将这些前缀函数转换为postfix(你应该在网上找到postfix的前缀 - 我的假设是你不知道“前缀”术语)。

编辑:基本上只是首先转换参数并按顺序输出它们,然后追加函数的名称。

答案 1 :(得分:1)

+这样的二元运算符可被视为+(x,y) 类似地,将sin,cos等函数视为一元运算符。因此,sin(x + y)* z可以写为x y + sin z *。你需要给这些一元功能特殊待遇。

答案 2 :(得分:1)

你必须自己解决的代码。以您的具体案例为例可能有助于您入门; sin(x + y) * z的后缀形式为:

  

x y + sin z *

请注意,在这个示例中,对两个值(+*)进行了一些操作操作,其他一个(sin

答案 3 :(得分:1)

如果您正在寻找一种算法,为您提供转换中缀到postfix,包括函数调用支持,您可以使用下面的伪代码(看起来像python代码)。我已经为我的案子写了这个,但还没有经过考验。如果您发现任何错误,请告诉我。

我也为此编写了一个Java实现。

此外,有关此实施的注意事项很少:

  1. 此算法假设中缀为令牌流。它不解析表达式字符串。因此,每个令牌都可以被识别为操作数,运算符,函数调用等。

  2. 有7种不同的令牌:

    • 操作数X,Y等
    • 左派 - (
    • 正确的Paranthesis - )
    • 运营商 - +,*
    • 函数调用开始 - sin(
    • 函数调用结束 - sin(x
    • 逗号 - ,
  3. 函数调用开始在算法中由[字符表示,函数调用结束由]表示。请注意,函数调用终止是与Right Paranthesis )不同的标记,尽管它们可能由字符串表达式中的相同字符表示。

  4. 每个运算符都是二元运算符,其优先级和关联性是通常的含义。

  5. 逗号,是一个特殊的二元运算符,优先级为NEGATIVE INFINITY,关联性为LEFT(与+和*相同)。逗号运算符用于分隔函数调用的参数。所以对于函数调用:

    f(a,b,c)
    
    first comma separates a and b
    second comma separates a,b and c
    
    So the postfix for the above will be 
    ab,c,f
    
      

    您可以将逗号运算符视为添加到列表函数,该函数将第二个参数添加到第一个参数指定的列表中,或者如果两个值都是单个值,则会创建两个值的列表。

  6. 算法

    infix_to_postfix(infix):
    
        postfix = []
        infix.add(')')
        stack = []
        stack.push('(')
        for each token in infix: 
            if token is operand:
                postfix.add(token)
            if token is '[':
                stack.push(token)
            else if token is operator:
                if stack is empty OR 
                   stack[top] is '(' or stack[top] is '[':
                    stack.push(token)
                else if (operator)token['precedence'] > stack[top]['precedence'] OR
                   ( (operator)token['precedence'] == stack[top]['precedence'] AND 
                     (operator)token['associativity') == 'RIGHT' ):
                    stack.push(token)     
                else
                    postfix.add(stack.pop())
                    stack.push(token)
            else if token is '(':
                stack.push(token)
            else if token is ')':            
                while topToken = stack.pop() NOT '(':
                    postfix.add(topToken)
            else if token is ']':
                while True:
                    topToken = stack.pop()
                    postfix.add(topToken)
                    if topToken is '[':
                        break
    
            else if token is ',':
                while topToken = stack.peek() NOT '[':
                    postfix.add(topToken)
                    stack.pop()
                stack.push(token)
    

答案 4 :(得分:0)

尽管@mickeymoon算法似乎可以工作,但我仍然必须进行一些调整(对我而言不起作用),因此我认为它对其他实现(如Java的实现)可能会有帮助。基于https://en.wikipedia.org/wiki/Shunting-yard_algorithm

Stack<Token> stack = new Stack<>();
List<Token> result = new ArrayList<>();
//https://en.wikipedia.org/wiki/Shunting-yard_algorithm
// with small adjustment for expressions in functions. Wiki example works only for constants as arguments
for (Token token : tokens) {
    if (isNumber(token) || isIdentifier(token)) {
        result.add(token);
        continue;
    }
    if (isFunction(token)) {
        stack.push(token);
        continue;
    }


    // if OP(open parentheses) then put to stack
    if (isOP(token)) {
        stack.push(token);
        continue;
    }
    // CP(close parentheses) pop stack to result until OP
    if (isCP(token)) {
        Token cur = stack.pop();
        while (!isOP(cur)) {
            if (!isComma(cur)) {
                result.add(cur);
            }
            cur = stack.pop();
        }
        continue;
    }
    if (isBinaryOperation(token)) {
        if (!stack.empty()) {
            Token cur = stack.peek();
            while ((!isBinaryOperation(cur)
                    || (isBinaryOperation(cur) && hasHigherPriority(cur, token))
                    || (hasEqualPriority(cur, token) && isLeftAssociative(token)))
                    && !isOP(cur)
            ) {
                // no need in commas in resulting list if we now how many parameters the function need
                if (!isComma(cur)) {
                    result.add(cur);
                }

                stack.pop();
                if (!stack.empty()) {
                    cur = stack.peek();
                }
            }
        }
        stack.push(token);
        continue;
    }

    if (isComma(token)) {
        Token cur = stack.peek();
        while (!(isOP(cur) || isComma(cur))) {
            result.add(cur);
            stack.pop();
            if (!stack.empty()) {
                cur = stack.peek();//  don't pop if priority is less
            }
        }
        stack.push(token);

    }
}
while (!stack.empty()) {
    Token pop = stack.pop();
    if (!isComma(pop)) {
        result.add(pop);
    }

}
return result;

我用各种复杂的表达式(包括函数组成和复杂的参数)对其进行了测试(不适用于Wiki算法中的示例)。几个示例(e只是一个变量,min,max,rand-函数):

输入 :( 3.4 + 2 ^(5-e))/(1 + 5/5)

输出: 3.4 2 5 e-^ + 1 5 / + /

输入:2 + rand(1.4 + 2,3 + 4)

输出:2 1.4 2 + 3 4 + rand +

输入:最大(4 + 4,最小(1 * 10,2 +(3-e)))

输出:4 4 + 1 10 * 2 3 e-+最小最大值

我还用带有三个参数(其中每个参数本身是一个表达式)的复杂函数对其进行了测试,并且它的语言很好。

这是我的java function的github,它获取标记列表并以后缀表示法返回标记列表。这是the function,它从第一个函数获取输出并计算表达式的值