我有一个逻辑表达式,我想评估。 表达式可以嵌套,由T(True)或F(False)和括号组成。 括号“(”表示“逻辑或”。 彼此相邻的两个术语TF(或彼此旁边的任何其他两个组合)应该是ANDED(逻辑和)。
例如,表达式:
((TFT)T) = true
我需要一种算法来解决这个问题。我想到首先将表达式转换为析取或连接的正规形式,然后我可以轻松地评估表达式。但是,我找不到一个规范化表达式的算法。有什么建议?谢谢。
编辑:我误解了部分问题。在给定的逻辑表达式中,AND / OR运算符与每个括号“(”)交替。如果我们要通过树表示表达式,则AND / OR运算符取决于子树的深度级别。但是,它是最初给出最深层的树是AND树。我的任务是通过构造树来评估给定的表达式。 感谢下面的答案,澄清了问题的正确要求。
答案 0 :(得分:3)
从左到右扫描字符串。每次看到左括号时,都会向堆栈结构添加新条目。当您看到右括号时,弹出堆栈中最顶部的条目,将其评估为T或F,再次弹出堆栈,并将计算值附加到弹出的术语。继续,直到字符串结束,此时你将有一个T和F的字符串,并进行评估。
要评估一串Ts和Fs,如果全部为T则返回T,否则返回F.所以我们有......
evaluate(String expression)
1. subexpr = ""
2. for i := 1 to n do
3. if expression[i] == "(" then
4. stack.push(subexpr)
5. subexpr = ""
6. else if expression[i] == ")" then
7. result = evaluateSimple(subexpr)
8. subexpr = stack.pop() + result
9. else subexpr += expression[i]
10. return evaluate2(subexpr)
evaluate2(String expression)
1. for i := 1 to n do
2. if expression[i] == "F" then return "F"
3. return "T"
或类似的东西应该这样做(编辑:事实上,这并没有正确回答这个问题,即使是被问到的;请参阅评论。保持这一点,因为它仍然会朝着正确的方向前进)。请注意,您可以只使用一个函数evaluate来执行evaluate2所做的操作,但是在第一个循环之后,只有subexpr。这样可以避免通过不必要的副本,但是你可以用另一种方式减少代码。
答案 1 :(得分:2)
看了original problem后,我觉得你误解了它。
此问题与AND/OR
树有关,其中最深级别的节点为AND
个节点。其他节点的逻辑操作符由此因素决定 - 我们最初不知道它们是AND
还是OR
个节点,我们只给出最深层节点{{1节点 - 所以下一个更高级别的节点是AND
个节点,下一个更高级别是OR
节点,依此类推......逻辑操作符交换强>在树的不同深度之间。如果您查看他们提供的示例AND
树,这将变得清晰。
我解决这个问题的方法是先找出根节点的逻辑连接词。这可以通过对表达式进行单次扫描并跟踪括号的数量来完成。请注意,每个AND/OR
对应树中的新节点(树的下一级)。例如,请考虑表达式:
()
当你走过这个表达式时,首先我们遇到3个开括号,2个结束,1个开始,然后最后2个结束。如果您在此步行过程中获取在任何给定时间打开的最大括号数,则它将是此((F(TF))(TF))
树的最大深度(上例中为AND/OR
)。
那是什么意思?如果树的深度是奇数,则根节点是3
节点,否则根是AND
节点(因为连接词交替)。
一旦知道根节点的连接,就可以使用简单的基于堆栈的计算机来评估此表达式。我们需要记住,每次打开或关闭括号时,我们都需要翻转连接词。以下是评估上述表达式的方法:
OR
请注意,项目符号表示我们在表达式中的位置(如堆栈顶部)。然后我们继续如下:
AND |- (•(F(TF))(TF))
所以你得到OR |- ((•F(TF))(TF)) // flipped the connective because we jumped a node
OR |- ((F•(TF))(TF)) // nothing to evaluate on the current node, push F
AND |- ((F(•TF))(TF))
AND |- ((F(T•F))(TF))
AND |- ((F(TF•))(TF))
AND |- ((F(F•))(TF)) // Two booleans on top, T AND F = F (reduce)
OR |- ((F(F)•)(TF)) // Jumped out of a node, flip the sign
OR |- ((FF•)(TF)) // Completely evaluated node on top, (F) = F (reduce)
OR |- ((F•)(TF)) // Two booleans on top, F OR F = F (reduce)
AND |- ((F)•(TF))
AND |- (F•(TF))
OR |- (F(•TF))
OR |- (F(T•F))
OR |- (F(TF•))
OR |- (F(T•))
AND |- (F(T)•)
AND |- (FT•)
AND |- (F•)
的最终答案。这与shift-reduce parsing有一定的关系,但这种情况的减少取决于我们正在运行的AST的当前深度。我希望你能够将这个想法转化为代码(你需要一个堆栈和一个全局变量来跟踪当前正在运行的逻辑操作)。
最后,感谢您介绍该网站。您可能也喜欢this site。
答案 2 :(得分:1)
通过阅读您链接到的网站上的问题描述,我想您可能误解了这个问题。无论您是需要“逻辑AND”还是“逻辑OR”,这些术语取决于您从根节点下降了多少级别。
您可以通过将表达式解析为语法树,然后递归地遍历树,评估每个子表达式,直到您返回到根节点,轻松解决此问题。
答案 3 :(得分:1)
我使用与上述技术不同的技术解决了这个问题。我得到了在线系统评委的接受。
在树的第一层找出算子后(感谢@Asiri Rathnayake的想法),我递归地构造了表达式树。在施工期间,我扫描了字符串。如果字符是'(',那么我创建一个具有当前运算符值的节点并将其添加到树中。然后,我交替运算符并进行更深的递归级别。如果字符是'T',那么我创建一个值为“True”的节点,将其添加到树中并继续扫描。如果字符为“F”,则创建一个值为“False”的节点,将其添加到树中并继续扫描。最后,如果字符是')',然后我返回到递归的一个级别。
最后,我将完成表达式树。现在,我需要做的就是使用基本的递归函数对树进行简单的评估。
以下是我的C ++代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
struct Node {
char value;
vector<Node*> children;
};
void ConstructTree (int &index, string X, Node *&node, int op)
{
for(; index<X.size(); index++)
{
if(X[index]=='T')
{
Node *C= new Node;
C->value='T';
node->children.push_back(C);
}
else if(X[index]=='F')
{
Node* C= new Node;
C->value='F';
node->children.push_back(C);
}
else if(X[index]=='(')
{
if(op==0)
{
Node* C= new Node;
C->value='O';
node->children.push_back(C);
}
else
{
Node* C= new Node;
C->value='A';
node->children.push_back(C);
}
index++;
ConstructTree(index,X,node->children[node->children.size()-1],1-op);
}
else
return;
}
}
bool evaluateTree(Node* node)
{
if(node->value=='T')
return true;
else if(node->value=='F')
return false;
else if(node->value=='O')
{
for(int i=0; i<node->children.size(); i++)
if(evaluateTree(node->children[i])==true)
return true;
return false;
}
else if(node->value=='A')
{
for(int i=0; i<node->children.size(); i++)
if(evaluateTree(node->children[i])==false)
return false;
return true;
}
}
int main()
{
string X;
int testCase=1;
while(cin>>X)
{
if(X=="()")
break;
int index=0;
int op=-1;
int P=0;
int max=0;
for(int i=0; i<X.size(); i++)
{
if(X[i]=='(')
P++;
if(X[i]==')')
P--;
if(P>max)
max=P;
}
if(max%2==0)
op=0; //OR
else
op=1; //AND
Node* root = new Node;
if(op==0)
root->value='O';
else
root->value='A';
index++;
ConstructTree(index,X,root,1-op);
if(evaluateTree(root))
cout<<testCase<<". true"<<endl;
else
cout<<testCase<<". false"<<endl;
testCase++;
}
}