【问题标题】:Distributing AND over OR in a binary tree (Conjunctive Normal Form)在二叉树中将 AND 分布在 OR 上(合取范式)
【发布时间】: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;
}

【问题讨论】:

    标签: java recursion logic binary-tree


    【解决方案1】:

    如果 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 转换可能会使您的树呈指数级增长。所示的实现非常原始,没有使用任何增强功能来减少计算时间。

    【讨论】:

    • 谢谢...我没有考虑过迭代方法,因此我的分发方法的实现更加复杂和复杂,这要简单得多!我必须做的一件事是将一小段代码引入到默认返回的分发方法中,以便在返回之前设置 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
         */
    }
    

    注意 之前的代码没有经过测试,我假设了很多我不知道的事情 您的树的实现方式可能是您需要更新子节点中的父引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-07
      • 2020-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多