【问题标题】:Build a tree for string of parentheses为括号串构建树
【发布时间】:2012-08-29 17:31:16
【问题描述】:

我有一个

typedef struct node
{
   node* br;
   node* son;
};

给定一个字符串char* str,它由(,)的序列组成 我需要为这个字符串构建一棵树,例如: 对于字符串 (()())() 将构建以下树:

       br        br 
node ----- node ---- NULL
    |son    |son
    |      NULL
    |   br        br      br
   node --- node --- node --- NULL
           |son   |son
          NULL   NULL

【问题讨论】:

  • 你试过什么?
  • @Hbcdev - 我想到了递归解决方案

标签: c++ algorithm tree


【解决方案1】:

您的树有点难以阅读。我假设每个括号都是一个节点,所有嵌套的括号都是子节点。

这是一个简单的算法:

We start with a root node representing the empty string.
For each char c in the string s:
    if c == '(':
        create a new child node
        move to the new created node
    else:
        move to the parent node

这应该会给你一棵好看的树。 Ofc 你必须检查字符串是否有效,并在需要时进行补偿/纠正。

【讨论】:

  • 这个解决方案是我试过的,我的问题是它如何找到不正确的括号序列的树。这个解决方案没有发现错误
  • 您是否需要检测是否有错误或错误发生在哪里?因为给定一个好的字符串,你应该总是以根结尾。
  • 问题在于,在结束之前很难判断一个字符串是正确还是错误。回溯到原始错误也很困难,因为可能有不同的解决方案。
【解决方案2】:

此代码使用堆栈来存储与尚未看到其关闭括号的打开括号相对应的节点。当它看到一个开放的括号时,它将一个新节点推入堆栈。当它看到一个 close paren 时,它会从堆栈中删除当前的顶部节点,并使其成为其父节点的子节点,即位于其下方的节点。

#include <list>
#include <stack>
#include <functional>
#include <iostream>

struct Node {
    std::list<Node> children;
};

bool parse_parens (const char *str, Node *out)
{
    // stack of nodes for which open paren was seen but
    // close paren has not yet been seen
    std::stack<Node> stack;

    // push the virtual root node which doesn't correspond
    // to any parens
    stack.push(Node());

    for (size_t i = 0; str[i]; i++) {
        if (str[i] == '(') {
            // push new node to stack
            stack.push(Node());
        }
        else if (str[i] == ')') {
            if (stack.size() <= 1) {
                // too many close parens
                // (<=1 because root has no close paren)
                return false;
            }
            // Current top node on stack was created from the
            // open paren which corresponds to the close paren
            // we've just seen. Remove this node it from the stack.
            Node top = std::move(stack.top());
            stack.pop();
            // Make it a child of the node which was just below it.
            stack.top().children.push_back(std::move(top));
        }
        else {
            // bad character
            return false;
        }
    }

    if (stack.size() > 1) {
        // missing close parens
        return false;
    }

    // return the root node
    *out = std::move(stack.top());
    return true;
}

bool print_parens (const Node &node)
{
    for (std::list<Node>::const_iterator it = node.children.begin(); it != node.children.end(); ++it) {
        const Node &child = *it;
        std::cout << "(";
        print_parens(child);
        std::cout << ")";
    }
}

int main ()
{
    Node root;
    bool res = parse_parens("(())()(()())", &root);

    if (!res) {
        std::cout << "Error parsing!\n";
        return 1;
    }

    print_parens(root);
    std::cout << "\n";

    return 0;
}

这使用std::list 来存储兄弟节点,这比您建议的更容易使用。但是同样的算法也应该在那里工作。

【讨论】:

    【解决方案3】:

    您可以使用堆栈来实现这一点,一旦找到左括号,然后将此节点添加到堆栈中。如果再次左括号将子元素添加到堆栈的最顶部元素。在右括号中从堆栈中删除节点。就是这样。

    【讨论】:

    • 可以通过检查堆栈节点是否存在右括号来找到不一致的括号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多