具有功能支持的调车场算法

问题描述 投票:-1回答:1

我发现了Internet上Shunting-yard算法的这种实现(Infix to Postfix with function support

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)

我尝试将其移植到C ++,但我不明白我在哪里错那是我的代码:

    #include <iostream>
    #include <sstream>
    #include <stack>
    #include <string>

    using namespace std;

    string magic(string& infix){
       const string ops = "-+/*%^";
       string postfix;
       stringstream ss;
       stack<char> s;

       string token;
       infix+=")";
       s.push('(');
       for(int c = 0; c<infix.length(); ++c){
        for(int op = 0; op<ops.length(); ++op){
            if(infix[c] == ops[op])
                postfix+=infix[c];
        }
        for (int op = 0; op<ops.length(); ++op){
            if(infix[c]=='['){
                s.push(infix[c]);
            }else if(infix[c] == ops[op]){
                if(s.empty() || s.top()=='(' || s.top()=='[')
                    s.push(infix[c]);
                else if(0){
                    // cose con le precedenze
                }else{
                    s.pop();
                    postfix+=s.top();
                    s.push(infix[c]);
                }
            }else if(infix[c]=='('){
                s.push(infix[c]);
            }else if(infix[c]==')'){
                while(s.top() != '('){
                    s.pop();
                    char topc = s.top();
                    postfix += topc;
                }
            }else if(infix[c]==']'){
                while(true){
                    s.pop();
                    char topc = s.top();
                    postfix+= topc;
                            if(topc == '[')
                                    break;
                }
            }else if(infix[c]==','){
                while(s.top()!='['){
                    char topc = s.top();
                    postfix += topc;
                    s.pop();
                }
                s.push(infix[c]);
            }
        }

    }

    return postfix;

   }

   int main() {

      string infix = "[ sin ( 2 , 5 ) ] + 3 ^ ( 4 * ( 5 * ( 6 - 1 ) ) )";

      cout << "infix:   " << infix << '\n';

      cout << "postfix: " << magic(infix) << '\n';

      return 0;
    }

如果您不能用C ++开发,我有什么替代方法?有做类似事情的算法更适合该问题吗?欢迎所有代码答案,谢谢。

c++ pseudocode infix-notation shunting-yard
1个回答
0
投票

您从该答案中转换代码时会遇到很多问题,其中包括答案中一个非常明显的错误,即第二个ifif token is '[')应该为else if。但是请注意,第一个if中的条件是if token is operand,但是您的翻译大致是if token is operator。这两个问题肯定足以阻止您的代码按需工作。

除此之外,重要的是要阅读引用答案中的注释,该注释指出伪代码基于已被标记化的输入;该代码不应直接应用于输入。特别是,数字和变量名称应该是令牌流中的单个元素。另外,请参见注释3,其中解释了[]的来源;它们不在输入流中,因此必须由令牌发布者创建。

通常,在尝试编写实现时,特别是在移植的是伪代码时,尝试了解算法的工作原理很有帮助。 (有关伪代码的最重要的事情是,它不是代码,因此永远不会经过测试。即使是非常有经验的编码人员也很少注意到很小的错误,这些错误会误入伪代码。如果有一种运行伪代码的方法,这样的错误将被立即检测到,但是由于没有发现,因此在测试具体实现时会出现这些错误。总之,caveat receptor。]

the shunting-yard algorithm on Wikipedia有一个合理的解释。特别是,如果已知函数的名称,则Wikipedia页面上的伪代码将处理函数调用。

关于调车场的另一讨论,包括关于在标记输入时如何识别函数调用和一元运算符(前缀和后缀)的注释,请参见this answer on SO,其中还包括伪代码。

关于三个Shunting Yard演示文稿的一个有趣的事实是,它们各自具有将函数调用转换为后缀的样式。您需要解决的具体问题是后缀函数调用是模棱两可的,除非您以某种方式知道使用了多少个参数。 infix调用中的括号使参数计数显式,但是无括号的表示形式(如postfix)需要不同的机制。

使用逗号作为建立参数列表的二进制运算符,就像您尝试移植的代码一样,是一种有趣的策略。但是,所提供的伪代码无法处理没有参数的功能。 (此外,[令牌还必须包含函数名称这一事实也没有得到很好的解释。)

另一方面,维基百科代码依赖于识别用作功能的标识符。并且它要求每个这样的函数都具有众所周知的参数数量。在计算器中这是可以的,其中的函数通常仅限于sindigamma之类的东西,但是在通用编程语言中这是有问题的。

我的解决方案将CALL运算符插入到后缀输出中;如注释所示,实际实现中还应该在CALL之前插入提供的参数数量作为附加值。不过,实现细节还无法很好地解释。 (对不起!)

© www.soinside.com 2019 - 2024. All rights reserved.