C 分流码算法和表达树实现

C++ shunting yard algorithm and expression tree implementation

本文关键字:实现 分流 算法      更新时间:2023-10-16

我是C 的新手,并使用分流码算法来构建表达树。我已经遇到了几天的问题。我正在尝试获取根节点的值,但它失败了。


infix输入

(1+2)*(3/4)-(5+6)

以下代码是基于划痕码的函数:

vector<string> infixToRPN(vector<string> tokens) {
    vector<string> output;
    stack<string> stack;
    string o1;
    string o2;
    //traverse tokens
    for (int i = 0; i < tokens.size(); ++i) {
        // if token is operator
        if (isOperator(tokens[i])) {
            string o1 = tokens[i];
            if (!stack.empty()) {
                string o2 = stack.top();
                while (isOperator(o2) && comparePrecendence(o1, o2) <= 0) {
                    // pop off o2 and on to the output;
                    stack.pop();
                    output.push_back(o2);
                    if (!stack.empty())
                        o2 = stack.top();
                    else
                        break;
                }
            }
            //push o1 on to the stack;
            stack.push(o1);
        }
        //if token is left bracket
        else if (tokens[i] == "(") {
            stack.push(tokens[i]);
        }
        //if token is right bracket
        else if (tokens[i] == ")") {
            string topToken = stack.top();
            while (stack.top() != "(") {
                output.push_back(topToken);
                stack.pop();
                if (stack.empty()) break;
                topToken = stack.top();
            }
            if (!stack.empty()) stack.pop();
        }
        // if token is number and add it to ouput;
        else
        {
            output.push_back(tokens[i]);
        }
    }
    //pop the rest of token
    while (!stack.empty()) {
        string restToken = stack.top();
        output.push_back(restToken);
        stack.pop();
    }
    return output;
}

测试结果表明解析器似乎有效:

12+34/*56+-

所以我想错误可能发生在我的buildtree函数中。建造后,getRoot((函数返回的值始终与正确的值不一致。就我而言,当我得到" 0"时,根应为" - "。

 ExprTree ExprTree::buildTree(vector<string> tokens){
    ExprTree t ;
    TreeNode * n, * n1, * n2;
    TreeNode * r = t.getRoot();
    vector<string> postfix = infixToRPN(tokens);
    stack<TreeNode *> stack;
    for (int i = 0; i < postfix.size(); ++i) {
        //if number

        if (!isOperator(postfix[i])) {
            n = createOperatorNode(postfix[i]);
            stack.push(n);
        }
        else // if operator
        {   
            n= createOperatorNode(postfix[i]);
            if (!stack.empty())
                t = ExprTree(stack.top());
            // pop two tree nodes 
            n1 = stack.top();
            stack.pop();
            n2 = stack.top();
            stack.pop();
            //set children nodes;
            n->setLeftChild(n2);
            n->setRightChild(n1);
            stack.push(n);
        }
    }
    return t;
}

您的算法看起来不错,但是您返回的树存在错误。

从RPN符号中构建节点后,堆栈中应剩下一个节点。返回该节点的节点或该节点的树。

因此,基本上是:

for (int i = 0; i < postfix.size(); ++i) {
   // build tree
}
// enforce that there is only one node on the stack
return ExprTree(stack.top());

您也可以随时跟踪顶部,但是如果这样做,则必须使新操作员节点成为顶部。在您的代码中,您将右手操作装置为顶部。

请注意,在这种情况下,您还应该在处理数字时跟踪顶部,否则,当您的表达仅由一个数字组成时,您将具有null Top节点。另请注意,如果正确执行此操作,您的顶部将永远是将其推入堆栈的最后一项;换句话说,堆栈的顶部。