在二叉树中将 AND 分布在 OR 上(合取范式)
Posted
技术标签:
【中文标题】在二叉树中将 AND 分布在 OR 上(合取范式)【英文标题】:Distributing AND over OR in a binary tree (Conjunctive Normal Form) 【发布时间】:2013-06-18 19:02:05 【问题描述】:我正在尝试转换二叉树,例如
OR (Implementation of Operator - a specialisation of TreeNode... see below)
|-A (Implementation of TreeNode... see below)
|-OR
|-B
|-AND (Implementation of Operator - a specialisation of TreeNode... see below)
|-C
|-OR
|-D
|-E
转换为等效的连接范式 (CND) 表示。我相信因为我只使用逻辑 OR + AND 运算符,所以我必须执行的唯一步骤是 AND 在 OR 上的分布。这将在 CNF 中生成以下树(出于我的目的仍然是二进制):
AND
|-OR
| |-A
| |-OR
| |-B
| |-OR
| |-E
| |-D
|-OR
|-A
|-OR
|-B
|-OR
|-E
|-C
我在创建算法来执行此操作时遇到问题...到目前为止,我有以下骨架,它将自下而上重新编写树(注意对重构的递归调用):
public TreeNode reconstruct(TreeNode treeNode)
if(treeNode instanceof Operator)
TreeNode left = reconstruct(((Operator)treeNode).getLeft());
TreeNode right = reconstruct(((Operator)treeNode).getRight());
return distribute(treeNode, left, right);
else
return node;
使用类:
-----------
| TreeNode | // Interface
-----------
^
|
-----------
| Operator | // Interface
-----------
| getLeft() |
| getRight()|
| setLeft() |
| setRight()|
-----------
有人可以建议一个可以转换为 CNF 的分发实现吗?
// EDIT 1(在 nif 回答之后)
private Node distribute(TreeNode node, TreeNode left, TreeNode right)
if (node instanceof Or)
if (left instanceof And)
// distribute right over left AND
return
new And(
new Or(((Operator)left).getLeft(), right),
new Or(((Operator)left).getRight(), right)
);
else if (right instanceof And)
// distribute left over right AND
return
new And(
new Or(((Operator)right).getLeft(), left),
new Or(((Operator)right).getRight(), left)
);
if(node instanceof Operator)
((Operator)node).setLeft(left);
((Operator)node).setRight(right);
// default
return node;
【问题讨论】:
【参考方案1】:如果 AND
和 OR
是您正在使用的唯一运算符,那么将您的树转换为 CNF 应该不难。您所要做的就是找到OR(AND(X,Y), Z)
或OR(Z, AND(X,Y))
形式的结构并使用分布规律。
private static TreeNode distribute(TreeNode n, TreeNode left, TreeNode right)
if (n instanceof Or)
if (left instanceof And)
// distribute right over left AND
return new And(new Or(left.getLeft(), right),
new Or(left.getRight(), right));
else if (right instanceof And)
// distribute left over right AND
return new And(new Or(right.getLeft(), left),
new Or(right.getRight(), left));
// no change
return treeNode;
此算法必须应用于树的所有节点,直到树不再更改。将算法应用于节点的顺序无关紧要。直观地说,算法的重复应用将拉起所有AND
节点超过OR
节点,直到树在CNF 中。
TreeNode root = ....;
while (true)
TreeNode transformedRoot = reconstruct(root);
if (root.equals(transformedRoot))
break;
root = transformedRoot;
// root is now in CNF
注意:请注意,CNF 转换可能会使您的树呈指数级增长。所示的实现非常原始,没有使用任何增强功能来减少计算时间。
【讨论】:
谢谢...我没有考虑过迭代方法,因此我的分发方法的实现更加复杂和复杂,这要简单得多!我必须做的一件事是将一小段代码引入到默认返回的分发方法中,以便在返回之前设置 TreeNode 的左侧和右侧,但仍然是一个很好的答案!我已将更改后的代码包含在原始问题的编辑中【参考方案2】:我建议您查看树的导航方式,在您的代码中看起来像是深度优先搜索,因此您将从最深的分支(Deepest 运算符)开始您必须设计您的方法distribute
期望该顺序并应用以回溯方式对子节点的分配法则。
distribute 方法应该做的一个非常笼统的描述是:
必须应用哪种分配律的流程取决于 关于父节点的操作类型和子节点。 每个子节点可以是一个算子或一个值,根据这个组合做规律所要求的分布。
我想告诉你的伪代码是:
if parent node is OR type
if child nodes are OPERATOR-VALUE combination
if OPERATION is AND type
apply correspondig distribution
return the new parent
else
apply correspondig distribution
return the new parent
if child node are VALUE-VALUE combination
return parent
if parent node is AND type
if child nodes are OPERATOR-VALUE combination
if OPERATION is AND type
apply correspondig distribution
return the new parent
else
apply correspondig distribution
return the new parent
if child nodes are VALUE-VALUE combination
return parent;
一个实现示例:
public TreeNode distribute(TreeNode parent,TreeNode leftChild, TreeNode rightChild)
if( !(leftChild instanceof Operator) && !(rightChild instanceof Operator) )
/*There is nothing to do */
return parent;
if( parent.getType() == 'OR')
/*
Apply distributive laws and return the new branch
for example:
*/
if ( (leftChild instanceof operator) && !(rightChild instanceof Operator) )
TreeNode operatorLeftChild = leftChild.getLeftChild();
TreeNode operatorRightChild = leftChild.getRightChild();
if(leftChild.getType() == 'AND' )
/*
Applying distributive laws:
rightChild OR (operatorLeftChild AND operatorRightChild)
-> (rightChild OR operatorLeftChild) AND (rightChild OR operatorRightChild)
*/
TreeNode newBranch = new Operator("AND");
/*new Left child*/
TreeNode newLeftChild= new Operator("OR");
newLeftChild.setLeftChild(rightChild);
newLeftChild.setRightChild(operatorLeftChild);
/*new Richt Child */
TreeNode newRightChild= new Operator("OR");
newRightChild.setLeftChild(rightChild);
newRightChild.setRightChild(operatorRightChild);
/*Setting the new Branch*/
newBranch.setLeftChild(newLeftChild);
newBranch.setRightChild(newRightChild);
return newBranch;
if( parent.getType() == 'AND')
/*
Else-If and distributive laws stuff
*/
/*
You can also implement this part wihtout the else-if code by implementing a true table
but is more abstract and less human redeable
*/
注意 之前的代码没有经过测试,我假设了很多我不知道的事情 您的树的实现方式可能是您需要更新子节点中的父引用。
【讨论】:
以上是关于在二叉树中将 AND 分布在 OR 上(合取范式)的主要内容,如果未能解决你的问题,请参考以下文章