Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何将命题逻辑树转换为连接范式(CNF)树_C++_C_Recursion_Conjunctive Normal Form_Prefix Tree - Fatal编程技术网

C++ 如何将命题逻辑树转换为连接范式(CNF)树

C++ 如何将命题逻辑树转换为连接范式(CNF)树,c++,c,recursion,conjunctive-normal-form,prefix-tree,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 { string val; // The data in this node. TreeNode *left

我有一根像绳子一样的绳子

     s="(=> P (OR (AND A (NOT B)) (AND B (NOT A))))";
并将其转换为输出此字符串的CNF,如

(或(非p)(或A B)) (或(非P)(或(非B)(非A)))

我是否需要创建一个结构树节点来保持该值

     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,即连接范式? 请给出一些算法细节。
在我看来,也许使用递归函数更好地解决了这个问题,但我仍然想不出如何使用递归。或者您有其他解决此问题的建议吗?

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

  • 首先,用
    和(p=>q,q=>p)
    替换等价性
    pq
    ,然后用
    或(q,非(p))
    替换等价性
    p=>q

  • 转换为否定范式:将所有
    NOT
    操作向下移动到树中,以便
    NOT
    操作仅绑定到原子(
    A
    B

  • 然后,
    CNF(和(x,y))
    的结果很简单:
    和(CNF(x,CNF(y))
    ,因为CNF喜欢在树中有
    的高度

  • CNF(或(和(x,y,z))
    的结果稍微复杂一点。在这里,我们将使用析取在连接上的分布规则,即
    或(和(x,y),z)
    相当于
    和(或(x,z),或(y,z))
    。实际上,
    CNF(或(和(x,y),z))
    将是
    和(或(CNF(x),CNF(z)),或(CNF(y),CNF(z))


  • 完成了。

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

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

    TreeNode*ParseAtom(const char*&p)
    :跳过atom(连续的非空格序列)的p。返回一个TreeNode,其中atom为值,左右为空

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

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


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

    请自己动手。遇到问题时,可以问一个特定的问题。但这里有一个提示:“递归下降解析器”.另一个提示:程序需要做的第一件事是什么?我只想知道一些算法并从中学习一些东西,这样我就可以做我自己的工作,我不想有人为我发布源代码。我确实很难找到有用的信息,但仍然不明白,这就是为什么我在这里问这个问题,我错了吗?在你写当然,你可以在谷歌上搜索“递归下降解析器”并在路上走很长时间。没问题,如果你觉得答案有用,请接受它!丽贝卡,我已经发布了一个答案,可以很容易地引导你找到一个完整的程序。那么你的算法是递归还是非递归?暗示(=>)呢在底部,X=>Y CNF:不是X和Y,如果字符串很长,事情会很复杂,而且会有很大的麻烦work@RebeccaAdrian解决了这个问题。是的,它是递归的……任何树遍历都是递归的。你看到“AND(CNF(x),CNF(y))”了吗例如?这是一个CNF的递归调用。对于一个有经验的程序员来说,这并不是那么多工作。如果你不是一个程序员,也许你应该从一个更简单的问题开始。@Rebecca在某些情况下,算法的输出将与输入的大小成指数关系,例如
    或(和(x_1,y_1),和(x_2,y_2),…和(x_n,y_n))
    结果将是
    或(z_1,z_2,…,z_n)形式的所有子句的连接
    每个
    Z_i
    都是
    X_i
    Y_i
    @AdrianPanasiuk Im使用您提到的相同方法。但是可以在树的一次遍历中应用所有分布规律。Mi问题是类似于a&b&c|d的东西会转换为((a | d)和((b&c)| d)),因此我必须进行两次遍历以获得所需的:((a | d)和((b | d)和(c | d))。是我做错了什么事还是这是意料之中的事?@Wyvern666尝试将
    视为n元而不是二进制-
    a&b&c | d
    变成
    或(和(a,b,c),d
    而不是
    或(和(和(a,和(b,c)),d)
    。实际上,没有必要在树中转换字符串,这会使事情变得复杂,对吗?我可以使用substr()和find()以及strcpy()之类的东西将其转换为CNF吗?@Rebecca当然需要将字符串转换为树,我刚刚告诉过你如何转换。