C++ 表达式树遍历以就地将表达式更改为 NNF
C++ Expression tree traversal to change expression to NNF in place
我想将表达式转换为否定范式。为此,我有一个使用智能指针的二叉表达式树。问题在于,当双否定出现在二进制表达式中时,删除双否定不起作用,尽管函数removeDoubleNot()
是在正确的时间调用的。因此,例如 ¬(A∨¬B( 变为 ¬A∧¬¬B 而不是 ¬A∧B,但它仅适用于 ¬¬B。我认为错误在evaluate()
但我还找不到它。也许递归是错误的?
// It is assumed that all Expressions are valid
std::shared_ptr<Expression> NNF::removeDoubleNot(std::shared_ptr<Not> expr) {
// Left is a Not -> remove both Nots
if (auto node = dynamic_cast<Not *>(expr->getLeft().get()))
return node->getLeft();
return expr;
}
std::shared_ptr<Expression> NNF::applyDeMorgan(std::shared_ptr<Not> expr) {
// And
if (auto node = dynamic_cast<And *>(expr->getLeft().get())) {
auto newLeft = std::make_shared<Not>(node->getLeft());
auto newRight = std::make_shared<Not>(node->getRight());
return std::make_shared<Or>(newLeft, newRight);
}
// Or
if (auto node = dynamic_cast<Or *>(expr->getLeft().get())) {
auto newLeft = std::make_shared<Not>(node->getLeft());
auto newRight = std::make_shared<Not>(node->getRight());
return std::make_shared<And>(newLeft, newRight);
}
return expr;
}
std::shared_ptr<Expression> NNF::removeImplication(const std::shared_ptr<Implication> &expr) {
auto newLeft = std::make_shared<Not>(expr->getLeft());
auto newRight = expr->getRight();
return std::make_shared<Or>(newLeft, newRight);
}
std::shared_ptr<Expression> NNF::moveNegationInwards(const std::shared_ptr<Not> ¬Expr) {
expr = applyDeMorgan(node);
if (auto node = std::dynamic_pointer_cast<Not>(expr))
expr = removeDoubleNot(node);
return expr;
}
std::shared_ptr<Expression> NNF::evaluate(std::shared_ptr<Expression> expr) {
if (expr == nullptr)
return nullptr;
// Implication
if(auto node = std::dynamic_pointer_cast<Implication>(expr)){
auto ret = removeImplication(node);
evaluate(ret->getLeft());
evaluate(ret->getRight());
return ret;
}
// Other binary than implication
if(auto node = dynamic_cast<Binary*>(expr.get())){
evaluate(node->getLeft());
evaluate(node->getRight());
return expr;
}
// Not
if(auto node = std::dynamic_pointer_cast<Not>(expr)) {
auto ret = moveNegationInwards(node);
evaluate(ret->getLeft());
evaluate(ret->getRight());
return ret;
}
return expr;
}
调用evaluate(ret->getLeft())
时,您没有使用返回值,因此您永远不会更改当前的子表达式。 因此,您需要将其更改为:
ret->setLeft(evaluate(ret->getLeft()));
权利也是如此。
您可能需要考虑使用[[nodiscard]]
来获取有关此类错误的编译器警告。
相关文章:
- (C++)分析树以计算返回错误值的简单算术表达式
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 提升精神:解析布尔表达式并简化为规范范式
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 使用正则表达式regex_search在字符串中查找字符串
- 如何确认我的constexpr表达式实际上已经在编译时执行
- 概念中的cv限定符需要表达式参数列表
- 为什么constexpr的性能比正常表达式差
- 对于结构,表达式必须是可修改的ivalue
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 将fold表达式与std::一起用于两个元组
- 断言中的Fold表达式在某些计算机上编译,但在其他计算机上不编译
- 标记 '","' 之前的预期主表达式
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 如何计算具有指定类型的表达式的相对精度和绝对精度
- 带有用户定义类的c++折叠表达式
- 即使使用调试编译标志,表达式也是"optimized out"
- holeMenuProgram.cpp:38:1 错误:'}'令牌之前的预期主表达式
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- C++ 表达式树遍历以就地将表达式更改为 NNF