在下面的内容中,您将看到一个数据结构,它非常类似于功能模型的简化版本(因为它们具有外观here)并且是树的某个版本。我已经用Java实现了数据结构,现在我试着去分析它。具体而言,我希望获得在给定特定特征模型时可能的所有元素组合。
元素是方框。未填充的圆圈表示可选元素(请记住o表示可选),填充的表示强制。必须包含根元素。由于这些规则,以下组合或元素列表是可能的:
现在,我想通过可视化搜索来获取它们,而不是通过Java程序。为此,我实施了几个课程:
Tree
存储整个要素模型(图形)。Element
是其中一个矩形。Edge
描述了直线和圆圈。Combination
拥有一种可能的组合(组合列表)。 在Element
课程中,我实施了一项功能,以获取名为recursiveConfiguration
的所有组合:
public List<Combination> recursiveCombination(List<Combination> combinations){
for(Combination c: combinations){
c.add(this);
}
// Iterate through all edges of the current element
for(Edge e: getEdges()){
int type = e.getType();
// In this case getChildren always returns only one feature.
Element child = e.getChildren().get(0);
List<Combination> childCombinations = child.recursiveCombination(combinations);
if(type == 1){
// If type is mandatory
combinations = childCombinations; // Line with compiler error
}else{
// If type is optional
combinations.addAll(childCombinations);
}
}
return combinations;
}
算法说明:
它使用一个元素的组合列表进行调用,这是一个空列表。在根元素1
上调用该函数。它将1
的第一个for循环添加到组合中(它使用DFS遍历树)。其次,该方法从元素2
开始调用,传递原始列表(包含1
)。从那里返回由元素1
和2
组成的配置。根据边缘的类型处理返回的列表(强制或可选,并相应地添加到原始列表)。在该特定情况下,列表应包含两个组合1
和1,2
。当第一个边缘下的子树(在这种情况下只有元素2
)完成时,处理下一个子树(3
,5
,6
)。
以下内容不再重要,请在水平栏下查看。
但目前我对递归感到困惑,因为当我调用它时,返回的combinations
列表为空。我相信这与治疗叶子的方式有关。因为目前这些都没有得到妥善处理(参见上面的粗体文字)。
有人有想法吗?当然,如果有必要,我会尝试更详细地解释这个问题,并感谢你在这个问题中提出的想法。
对原始问题的规范:让我们假设算法一般有效(我已经多次检查过)。所以我想我对Java的理解在程序的某些部分是不正确的。两个人认为可能很有趣:
The parameter configurations should not be assigned
,并且它显示Configure problem severity
行combinations = childCombinations;
。这可能是个问题吗?combinations
在第二个/第三个/ ...递归调用中而不是在返回后更改?目前程序产生的输出返回以下组合(显然不对):
感谢您的时间和精力!
答案 0 :(得分:0)
我认为你在开始时将节点添加到列表中的每个组合的逻辑是错误的,应该在之后完成。
正确的算法可能如下所示:
使用根节点调用递归函数。返回组合列表。
如果是叶子节点,则返回仅包含该节点的组合列表。
对于每个边缘:使用子节点调用递归函数并保存结果。
创建强制子项的所有可能组合。例如。有两个强制性孩子,一个有11个组合,另一个有7个,你得到11 * 7 = 77个组合。您基本上构建了所有强制组合的交叉产品,这是更简单的步骤。如果节点没有强制子节点,则它是一个组合列表,其中包含一个空组合(稍后将向其添加当前节点)。
与可选子项的组合结合使用。例如。有两个额外的可选儿童,3种和5种组合,你得到77 + 77 * 3 + 77 * 5 + 77 * 3 * 5 = 1848种组合。在这里你可以选择是否采用一个可选的分支,因此它很快爆炸,有3个分支a,b,c和x强制组合,你得到x + ax + bx + cx + abx + acx + bcx + abcx(取和不取a,b或c的所有组合)。
将调用函数的节点添加到每个组合并返回结果。
答案 1 :(得分:0)
因为我无法清楚地解释问题,所以无法发布解决方案。现在我将发布解决方案。首先,破坏惊喜:算法是正确的,因为我理解它,但在整个递归过程中相同的combinations
变量被改变。因此,同样的组合产生了四次。
解决方案是使用clone
方法,因此将List
更改为LinkedList
。
private LinkedList<Combination> recursiveConfiguration(LinkedList<Combination> combinations){
for(Combination c: combinations){
c.add(this);
}
// Iterate through all edges of the current node
for(Edge e: getEdges()){
int type = e.getType();
if((type == 1) || (type == 2)){
// If type is mandatory or optional.
// In this case getChildren always returns only one feature.
LinkedList<Combination> copyConfig = new LinkedList<>();
for(Combination c: configurations){
@SuppressWarnings("unchecked")
LinkedList<FeatureNode3> copy = (LinkedList<FeatureNode3>) c.getFeatureList().clone();
Combination config = new Combination();
config.setFeatureList(copy);
copyConfig.add(config);
}
FeatureNode3 child = e.getChildren().get(0);
LinkedList<Combination> childCombinations = child.recursiveConfiguration(copyConfig);
if(type == 1){
// If type is mandatory
combinations = childCombinations;
}else{
// If type is optional
combinations.addAll(childCombinations);
}
}
}
return combinations;
}
感谢您的时间和建议!