java - 在二叉树中分布 AND over OR(合取范式)

标签 java recursion logic binary-tree

我正在尝试转换二叉树,例如

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 的 distribute 实现吗?

//编辑 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;
}

最佳答案

如果 ANDOR 是您正在使用的唯一运算符,那么将您的树转换为 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 转换可能会使您的树呈指数增长。显示的实现非常原始,没有使用任何增强功能来减少计算时间。

关于java - 在二叉树中分布 AND over OR(合取范式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17238768/

相关文章:

java - 如何使java生成的缩略图更清晰

java - Leadbolt 应用程序墙无法正常工作

java - 如何将迭代方法转换为递归方法(Java)

xml - 使用模板设备的 XSLT 递归直通输出

java - 仅更改机器计数区

java - 未实现的接口(interface)有什么用?

java - 如何让 JProgressBar 转到 "wait"屏幕

java - 使用递归计算序列

java - Java ATM 项目中使用 If 语句进行切换

java - 将短语中字符的字符串值转换为莫尔斯电码的类