状态对象在生成新对象时覆盖以前的孩子
问题描述:
我在框架中使用回溯来处理带约束修剪的图着色问题。图形的每个可能的状态(即,可以放在图上的颜色的每个组合)由状态对象表示。该框架要求每个国家生产所有的孩子,选择最合适的孩子,并重复寻找最佳解决方案,并沿途修剪。我碰到的麻烦是这样的:状态对象在生成新对象时覆盖以前的孩子
当我在一个状态下调用nextChild()时,它将由该状态产生的前一个孩子改变为刚刚产生的状态。
以下是我认为是我的代码的相关部分:
public State nextChild() {
// System.out.println("currentColor: "+ colors.get(currentColor) + " firstUncolored " + this.firstUncolored);
// previous line for debugging
GraphColoringState child = childSetup();
child.gcolors[firstUncolored] = colors.get(currentColor++);
if(this.currentColor == colors.size()){
this.currentColor = 0;
this.hasMoreChildren = false;
}
return child;
}
private GraphColoringState childSetup() {
GraphColoringState theClone = new GraphColoringState(graph, colors);
theClone.gcolors = this.gcolors;
theClone.firstUncolored = this.firstUncolored +1;
theClone.currentColor = 0;
return theClone;
}
当我制作和打印的孩子是这样的:
State s = new GraphColoringState(graph, colors);
System.out.println(s);
State s1 = s.nextChild();
System.out.println(s1);
State s2 = s.nextChild();
System.out.println(s2);
State s3 = s.nextChild();
System.out.println(s3);
我得到这样的输出:
, , , , , ,
Red, , , , , ,
Green, , , , , ,
Blue, , , , , ,
但是当我生产和打印这种方式:
System.out.println(s);
State s1 = s.nextChild();
State s2 = s.nextChild();
State s3 = s.nextChild();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
我得到这个不幸的输出:
, , , , , ,
Blue, , , , , ,
Blue, , , , , ,
Blue, , , , , ,
我说这个输出是不幸的,因为为了使回溯框架的工作,我需要所有这些孩子的存储在同一时间,不同的值。我曾尝试在每个州内使用数组实例变量来存储它的子项,但无济于事。
为什么我的代码改变了我已经生成的孩子的值?
请谢谢! :)
答
gcolors是你设置为新的子值
theClone.gcolors = this.gcolors;
然后修改gcolors在nextChild()数组
child.gcolors[firstUncolored] = colors.get(currentColor++);
为了避免这样的错误,你可以使用一个改为不可修改的列表。
答
原来,问题是在这个行:
theClone.gcolors = this.gcolors;
这导致所有国家的共享一个阵列表示每个节点的颜色。我真正想要的是每个国家拥有自己的阵列。
更改该行:
theClone.gcolors = this.gcolors.clone();
是需要所有。感谢大家的帮助!
我不知道我明白 - 我应该让gcolors变量最终?由于我的代码试图修改它,是不是只是抛出异常? – 2014-11-08 19:45:56
如果你想保留年龄较大的孩子,那么你不能覆盖他们的状态。你可以使GraphColoringState不变,方法是使所有变量都是最终的,并用列表替换gcolors数组。通过调用Collections.unmodifiableList(..)将列表包装到一个不可修改的列表中,确保该列表也是不可变的。这样,你不可能意外地改变前一个孩子的状态。但是,原来的错误似乎是你复制gcolors数组然后修改它。 – avidD 2014-11-08 19:56:34
我明白了。 那么,我找到了一个解决方案 - 我只是改变了行 theClone.gcolors = this.gcolors; 阅读 theClone.gcolors = this.gcolors.clone(); 真的非常简单,我可能不需要打扰你们都与它。 谢谢你的建议,祝你有美好的一天! – 2014-11-08 20:35:48