我认为如果您将每个表达式建模为一个有根
有向无环图(DAG),那么您就有一个可以解决的案例。
我假设这个图是
无环的,因为您的最终目标是找到布尔代数运算的结果(如果图中存在循环,那么它将毫无意义)。
但是,即使您的图结构有意义地是循环的,那么您的目标搜索术语仍然应该是
循环图,并且它仍然应该有解决方案。
$expression = '!state1||state4&&(!state2||state5)'
在你的例子中,你有一个根节点和两个子DAG。
EXPRESSION as a Rooted DAG:
EXPRESSION
|
AND
___/ \___
OR OR
/ \ / \
! S_1 S_4 ! S_2 S5
您的邻接表是:
expression_adj_list = [
expression => [ subExp_1, subExp_2 ] ,
subExp_1 => [ ! S_1, S_4 ],
subExp_2 => [ ! S_2, S5 ]
]
现在,您可以通过
广度优先搜索算法或
深度优先搜索算法或您自定义的调整算法来遍历此图。
当然,如果这样更适合您并且更容易,您可以多次访问具有键和值的邻接列表。
您将需要一个
查找表来教授您的算法。例如,
- S2 && S5 = 1,
- S1 or S4 = 0,
- S3 && S7 = -1(可能会抛出异常)
最终,下面的算法可以解决您的表达式结果。
$adj_list = convert_expression_to_adj_list();
$root = 'EXPRESSION';
q[] = $root;
$results = [];
while ( ! empty(q)) {
$current = array_shift($q);
if ( ! in_array($current, $results)) {
if (isset($adj_list[$current])) {
$children = $adj_list[$current];
$bool = is_calculateable($children);
if ($bool) {
$results[$current] = calc($children);
}
else {
array_unshift($q, $current);
}
foreach ($children as $child) {
if (is_subexpresssion($child) && ! in_array($child, $results)) {
array_unshift($q, $child);
}
}
}
}
}
return $results[$root];
这种方法还有一个很大的优势:如果您将表达式的结果保存在数据库中,那么如果一个表达式是根表达式的子表达式,那么您就不需要重新计算它,只需使用数据库中子表达式的结果。通过这种方式,您始终具有两级深度DAG(根和其子级)。