我有一个像字符串
的字符串 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,这是合法的正常形式? 请给出一些算法细节。 从我的角度来看,也许使用递归函数更好地解决了这个问题,但我仍然想不出如何使用递归。或者你有其他建议来解决这个问题?
答案 0 :(得分:4)
假设您将函数命名为CNF
,取一棵树并在CNF中返回树。
首先,将等效p<=>q
替换为AND(p=>q,q=>p)
,然后将含义p=>q
替换为OR(q,NOT(p))
。
转换为否定正常形式:将所有NOT
操作移到树下,以便NOT
操作仅绑定到原子(A
,B
)
然后,CNF(AND(x,y))
的结果很简单:AND(CNF(x),CNF(y))
,因为CNF就像树中的AND
一样高。
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))
。
你已经完成了。
答案 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 ++中的保留字),它应该是一个枚举,而不是一个字符串。