我正在完成这项家庭作业,将命题逻辑陈述翻译成合一的正常形式。我遇到的问题是解析可能复杂的括号级别。这个问题需要以正确的顺序解决,我认为递归应该先用于解决内部括号,然后再向外移动,但我无法弄清楚如何实现我的想法。该程序需要用Java编写。有人可以帮忙吗?
答案 0 :(得分:1)
您能举例说明您要转换为CNF的声明吗?我在想你的意思是在起始逻辑语句中有括号,但它会有所帮助。
与此同时,我会说你不需要递归......但是堆栈会非常有用:)将项目及其数学运算推送到堆栈上,然后将它们弹出并在适当的时候对它们进行操作。由于它的功课我不会详细介绍,但是你会发现你将推 - 推 - 推 - 弹 - 乘 - 推 - 推 - 弹 - 加 - 弹 - 除......使用堆栈作为一种关注当前操作的方法。
对Postfix Notation的调查也很有用,可能有所帮助......即使维基百科上的文章也会给你一些想法(尽管那里有更多以计算机科学为导向的文章)。
免责声明:我没有考虑我的例子中那些推送和弹出的数量或顺序:)
的更新强>
您不需要多次传递数据,并且可以即时转换为CNF。
你正朝着正确的方向前进,所以有些帮助/提示:
减少你的榜样:
F→(E⋀(A→B))
转换的第一步看起来像这样(我假设您已经深入了解了基础逻辑转换规则,并且它只是您正在编写的代码):
F→(E⋀(A→B))
¬F⋁(E⋀(A→B))
¬F⋁(E⋀(¬A⋁B))
在CNF后缀中,它将如下所示:
F¬EA¬B⋁⋀⋁ // (Parentheses are obviated in postfix notation)
要实现这一目标,请从左到右一次读取初始逻辑语句...将操作数推送到操作数堆栈,将操作符推送到操作符堆栈。
在应用运算符时,从操作数堆栈中弹出所需的操作数,应用运算符,并将生成的字符串作为新操作数推回堆栈。
结束括号或低优先级操作会触发pop-apply-push。整件事看起来像这样:
Operand Operator
Stack Stack
---------- ----------
Read F: Push onto Operand stack F ........ ..........
Read →: On-the-fly conversion (→ becomes ¬⋁)
Unary Operator ¬ pops F from Operands; applies it; pushes back to Operands
¬F ....... ..........
Push ⋁ onto the op-stack ¬F ....... ⋁ .......
Read (: Discard
Read E: Push onto Operands stack ¬F E .... ⋁ ......
Read ⋀: Push onto Operators stack ¬F E .... ⋁⋀ .....
Read (: Discard
Read A: Push onto Operands stack ¬F E A .. ⋁⋀ .....
Read →: On-the-fly conversion (→ becomes ¬⋁)
Unary Operator ¬ pops A from Operands; applies; pushes back to Operands
¬F E ¬A . ⋁⋀ .....
Push ⋁ onto Operators stack ¬F E ¬A . ⋁⋀⋁ ....
Read B: Push onto Operands stack ¬F E ¬A B ⋁⋀⋁ ....
Read ): Triggers Operators/Operands pop; applies; pushes back to Operands
(After, there are three operands on the Operands stack)
¬F E (¬A⋁B) ⋁⋀ ....
Read ): Triggers Operators/Operands pop; applies; pushes back to Operands
(After, there are two operands on the Operands stack)
¬F (E⋀(¬A⋁B)) ⋁ ....
No more reads: Final Operators/Operands pop/apply/push (result is output)
¬F⋁(E⋀(¬A⋁B))
警告和注释:
这只是一个正确方向的开始......你将不得不处理像运营商优先权这样的问题(即你先推动并采取行动,或者现在弹出并采取行动)。您会发现您的决定是基于您阅读的下一个字符(而不是在右括号中,正如我上面暗示的那样)。
这听起来比它复杂......上面的伪代码不会超过12-15行。但是,我还没有解决的复杂问题......< - >函数必须以类似于→高于......的方式建模......你必须采用这种思路并实现所有的转换规则。
隐含的括号可以让你绊倒,例如
6 * (8 * 6) + 4
真的是
(6 * (8 * 6)) + 4
如果您没有正确处理运算符优先级,最终可能会出现类似
的内容686*4+*
这给你312,而不是正确答案(292)。
如果您在阅读本文中的unicode逻辑符号时遇到问题,请告诉我们;我可以使用标准字符重做它,但它在uni中读得更好:)
HTH,
詹姆斯
PS:一个漂亮的小程序,说明了后缀在这里:
http://fac-web.spsu.edu/cs/faculty/bbrown/web_lectures/postfix/
答案 1 :(得分:0)
伪代码:
parseRestOfString (int openParens, String rest) {
c = rest (0);
if (c == ')' && openParens == 0) ...
这会给你一个提示吗?
答案 2 :(得分:0)