我完全坚持我的一项任务,可以使用一些帮助。
我们正在实现一个树类,它存储和评估二进制表达式。以下是一个这样的表达式的示例:(MAJ(AND 3 4)(OR 1 2 3)(NOT 5)4)。这是指这棵树:
树以LCRS表示形式提供给我们,我们正在构建一个类来对其执行各种操作,例如查找树中的最大数字,查找特定操作符的编号或打印原始文件导致给定树的公式。我已经弄清楚所有这些,通过几个小时的头部刮擦和用于跟踪大型递归函数的纸叠。
但我无法弄清楚最后需要的功能,即
bool evaluate(const vector<bool> &values, Tree_Node* p)
此函数使用bool向量提供的真值来评估表达式(例如,如果值[3]和值[4]都为真,则(AND 3 4)将为真)。我花了很多时间寻找答案,并认为我正在使用表达式树,但在LCRS表示中无法找到它的工作原理。
我无法弄清楚递归。我把它分成了所有可能的情况,但是当你考虑不同的运算符时,有很多这样的情况。为了保持简洁,我会说我的主要问题是:
如何评估每个子树?例如,在LCRS树中,
AND
/
3
\
4
我看到我需要深入到4,意识到它是最简单的(基础)情况,然后开始递归到AND,但是当我回来时我看不到如何获得正确的值到AND。我需要额外的参数吗?也许传递下来的操作,或使用某种下面的额外指针?
//一些澄清的东西
四个运营商是:
(假设SO上的人理解并且,或者&amp; not。)
Node结构是一个典型的结构:
struct Tree_Node {
std::string data;
Tree_Node* left_child;
Tree_Node* right_sibling;
}
Tree类也是标准的,除了赋值的附加函数, 我可以在必要时发布代码,但它有你期望的树操作,并且正确编译和测试,问题只是关于这个函数。
我在我和其他家庭作业之间的桌子上敲我的头......哦,CS专业的生活。一如既往的任何帮助都非常感谢。
编辑:
非常感谢帮助我的每个人。我在这里得到的所有答案都帮助我解决了问题。有时它有助于获得新的视角。另外,std :: pair对我来说是新的!有趣,因为我有一个我自己的模板类,它做同样的事情......猜猜是时候退休了那个人!
我将在完成作业后发布我的功能和分析,以供将来参考。
编辑:
按照承诺,完成的功能。 count_children在功能上与rici布局的count函数相同,而TruthValues是一对std :: int,就像Counts一样。再次感谢那些帮助我解决这个问题的人。函数switch_help在给定字符串时返回switch语句的相应数字(例如switch_help("MAJORITY") == 2
)。
bool BooleanFormula::evaluate(const vector<bool> & values, Tree_Node* p){
TruthValues truth_vals = TruthValues(0,0);
int control = switch_help(p->data);
switch (control){
case 1: //p->data = "MAJORITY"
truth_vals = count_children(values, p->left_child);
return (truth_vals.first > truth_vals.second);
//return true if there are more trues than falses
case 2: //p->data = "AND"
truth_vals = count_children(values, p->left_child);
return (truth_vals.second == 0);
//return true if there are no falses
case 3: //p->data = "OR"
truth_vals = count_children(values, p->left_child);
return (truth_vals.first >= 1);
//return true if there is at least one true
case 4: //p->data = "NOT"
return !(evaluate(values, p->left_child));
//return the inverse of what is obtained by evaluating the subtree
default: //p->data = some number
//in this case, we're just at a node with an index in it
return values[atoi((p->data).c_str())];
}
}
答案 0 :(得分:1)
如果我理解了结构,在每个子树上你有根运算符,第一个操作数作为根的左子,后续操作数作为右链接来自 第一个操作数,是吗?
然后,一般的评估方案如下:
bool evaluate(const vector<bool> &values, Tree_Node* p) {
bool result;
switch (p->op) {
case BASE:
return values[p->index];
...
case AND:
result = true;
for (op = p->left; op != nullptr; op = op->right)
result &= evaluate (values, op);
return result;
...
}
}
(这里我假设叶子包含value
数组中的索引。
答案 1 :(得分:0)
表达式树的递归评估包括:
反过来要求:
现在,让我们尝试稍微系统化。考虑一下您的操作 - NOT
,AND
,OR
和MAJ
- 并考虑如何计算操作数列表中每个值的值。具体来说,我们需要了解哪些列表?在所有情况下,以下两个数据就足够了(只有一个是必要的):
列表的值中有多少是TRUE
?
列表的值中有多少是FALSE
?
(或者,第二个可能是“列表中有多少个值?”,这显然是等价的。)
如果AND
个孩子的数量为0,则TRUE
为FALSE
;如果OR
个孩子的数量为0,则FALSE
为TRUE
;如果MAJ
个孩子的数量大于TRUE
个孩子的数量,则TRUE
为FALSE
。 (NOT
对操作数列表至少有两种推广,或者您可以将其限制为TRUE
子项数为0且FALSE
子项数为0的情况。 1。)
现在,假设我们已经将列表缩减为这两个值nTRUE
和nFALSE
,并且我们想要在列表中添加一个新元素(这将是递归步骤。)可以我们这样做?明显。如果新元素为TRUE
,我们会增加nTRUE
;如果新元素为FALSE
,我们会增加nFALSE
。瞧!
在C ++中,表示一对值的标准方法是std::pair
。使用它,我们可以表达我们的递归减少如下:
typedef std::pair<int, int> Counts;
Counts count(Tree_Node* node) {
if (!node) return Counts{0, 0};
Counts rest = count(node->right_sibling);
if (evaluate(node))
return Counts{rest.first + 1, rest.second};
else
return Counts{rest.first, rest.second + 1};
}
假设evaluate
返回一个布尔值。但是,如果evaluate返回Counts
个对象,使用{1,0}
表示true,{0,1}
表示false,我们可以使这更加优雅。然后我们可以写:
typedef std::pair<int, int> Counts;
Counts operator+(const Counts& a, const Counts& b) {
return {a.first + b.first, a.second + b.second};
}
Counts count(Tree_Node* node) {
if (!node)
return Counts{0, 0};
else
return evaluate(node) + count(node->right_sibling);
}
在这两种情况下,我都忽略了evaluate
的定义,这需要根据运营商的不同而有所不同。但我希望evaluate(node)
使用count(node->left_child)
的方式很明显。