このコードは、スタックを使用して、閉じ括弧がまだ表示されていない開き括弧に対応するノードを格納します。開いた括弧を見つけると、新しいノードをスタックにプッシュします。閉じ括弧を見つけると、現在の最上位ノードをスタックから削除し、その親の子 (そのすぐ下にあったノード) にします。
#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
、兄弟ノードを格納するために使用されます。これは、提案したものよりも簡単に操作できます。ただし、同じアルゴリズムがそこでも機能するはずです。