如何使这个树遍历更有效?

时间:2017-09-20 22:45:20

标签: c++ algorithm list data-structures tree

我有一个处理一组规则的项目。目前,规则由一个或多个子句组成,其语法如下:

A
A & B
A & B & C
etc

这编成如下:

struct Rule {
    list<Clause*> Clauses;
};

bool ProcessRule(const Rule* Rule) {
    for (const auto& Clause : Rule->Clauses) {
        if (!ProcessClause(Clause)) return false;
    }
    return true;
}

我的任务是实现一个互补的逻辑或构造,其语法如下:

A
A & B
A | B
A & B & C
A & B | C
A | B & C
A | B | C
etc

我选择了最明显的方法,并将Rule结构的实现从使用列表更改为使用树:

enum NodeType {
    LogicalAnd,
    LogicalOr,
    Leaf,
};

struct Node {
    NodeType Type;
};

struct LogicalNode : Node {
    list<Node*> Children;
};

struct LeafNode : Node {
    Clause* Clause;
};

struct Rule {
    Node* Root;
}

bool ProcessRule(const Rule* Rule) {
    return ProcessNode(Rule->Root);
}

bool ProcessNode(const Node* Node) {
    switch (Node->Type) {
        case LogicalAnd:
            for (const auto& Child : ((const LogicalNode*)Node)->Children) {
                if (!ProcessNode(Child)) return false;
            }
            return true;
        case LogicalOr:
            for (const auto& Child : ((const LogicalNode*)Node)->Children) {
                if (ProcessNode(Child)) return true;
            }
            return false;
        case Leaf:
            return ProcessClause(((const LeafNode*)Node)->Clause);
    }
}

这一切似乎都非常简单,但问题是使用完全相同的规则集相对严重的性能下降,大约15%左右。我通过分析器运行了两个版本,并且降级是由于ProcessNode()函数的开销,我假设由于switch语句和函数调用ProcessRule()被调用了数百万次。有没有办法减轻这种开销?这似乎有点过分,所以我觉得我可能会遗漏一些明显的东西。

1 个答案:

答案 0 :(得分:0)

删除开关并添加AndNodeOrNode类,并使用具有适当覆盖的虚函数。