如何将命题逻辑树转换为连接正规形式(CNF)树

时间:2013-04-18 19:22:01

标签: c++ c recursion conjunctive-normal-form prefix-tree

我有一个像字符串

的字符串
     s="(=> P (OR (AND A (NOT B)) (AND B (NOT A))))";

并将其转换为输出此字符串的CNF,如

(或(不是P)(或A B)) (或(不是P)(或(不是B)(不是A)))

我是否需要使用struct TreeNode来保存值?

     struct TreeNode {
            string val;         // The data in this node.
            TreeNode *left;   // Pointer to the left subtree.
            TreeNode *right;  // Pointer to the right subtree.
            //TreeNode *farther;//should I use farther or not in convert to CNF?
      };

如何将其制作成CNF,这是合法的正常形式? 请给出一些算法细节。 从我的角度来看,也许使用递归函数更好地解决了这个问题,但我仍然想不出如何使用递归。或者你有其他建议来解决这个问题?

2 个答案:

答案 0 :(得分:4)

假设您将函数命名为CNF,取一棵树并在CNF中返回树。

  1. 首先,将等效p<=>q替换为AND(p=>q,q=>p),然后将含义p=>q替换为OR(q,NOT(p))

  2. 转换为否定正常形式:将所有NOT操作移到树下,以便NOT操作仅绑定到原子(AB

  3. 然后,CNF(AND(x,y))的结果很简单:AND(CNF(x),CNF(y)),因为CNF就像树中的AND一样高。

  4. CNF(OR(AND(x,y),z))的结果有点复杂。在这里,我们将使用析取的分布规则,而OR(AND(x,y),z)相当于AND(OR(x,z),OR(y,z))。实际上,CNF(OR(AND(x,y),z))将为AND(OR(CNF(x),CNF(z)),OR(CNF(y),CNF(z))

  5. 你已经完成了。

答案 1 :(得分:2)

简单的递归下降解析器解决方案:

TreeNode* ParseExpression(const char*& p):如果p指向的字符串不以'('然后返回ParseAtom(p)开头,则移动p经过'(',调用ParseOperation(p),然后移动p经过')'并返回ParseOperation返回的值。

TreeNode* ParseAtom(const char*& p):跳过p经过原子(连续的非空间系列)。返回一个TreeNode,其中atom为值,左右为NULL。

TreeNode* ParseOperation(const char*& p):p指向的字符串应以运算符开头。将p移动到运算符之后,然后确定运算符占用的操作数。如果一个,调用ParseExpression(p)一次;如果两个,则调用ParseExpression(p)两次。然后返回一个TreeNode,其中运算符为值,并且一个或两个ParseExpression调用的结果为left和right(对于只有一个操作数的运算符,right应为NULL)。

设置指向原始字符串的指针;在该指针上调用ParseExpression;返回值是您的树,指针将指向字符串中的第一个表达式。

这解决了您的一个问题:如何将字符串转换为树。 Adrian Panasiuk解决了另一个问题,即如何将树转换为普通形式。由于你将要进行额外的树转换,你的节点中的“值”应该被称为“op”或类似的东西,代表“operator”(这是C ++中的保留字),它应该是一个枚举,而不是一个字符串。