我正在用Java构建一个模拟移动节点网络的程序。当节点发生碰撞时,他们有可能建立连接。我试图以一种使连接组件显而易见的方式存储图中的所有节点,因此我将其存储为一组列表,其中每个列表是一个组件,集合包含所有组件。 (每个组件的大小必须大于1。)
完整的代码在github上:https://github.com/IceCreamYou/ViralSpread
但这是重要的部分:
// Store the components in the "temp" variable while we calculate them.
// Each list is a component; the set contains all components.
HashSet<LinkedList<Person>> temp = new HashSet<LinkedList<Person>>();
// hardConnections is a set of all connections between the nodes.
// Each connection appears only once (e.g. if there is a connection from A to B
// there will not be a connection from B to A -- however each connection is
// considered bidirectional).
for (Person[] connection : hardConnections) {
// Each element of hardConnections is an array
// containing two connected nodes.
// "Person" is the node class.
Person a = connection[0], b = connection[1];
boolean bFound = false, aFound = false;
// If we've already added one of the nodes to a component,
// add the other one to it.
for (LinkedList<Person> component : temp) {
boolean bInComponent = false, aInComponent = false;
for (Person p : component) {
if (p.samePosition(b)) {
bInComponent = true;
}
if (p.samePosition(a)) {
aInComponent = true;
}
}
if (bInComponent && !aInComponent) {
component.add(a);
bFound = true;
break;
}
else if (!bInComponent && aInComponent) {
component.add(b);
aFound = true;
break;
}
else if (bInComponent && aInComponent) {
aFound = true;
bFound = true;
break;
}
}
// If neither node is in a component, create a new component containing both nodes.
if (!bFound && !aFound) {
LinkedList<Person> newComponent = new LinkedList<Person>();
newComponent.add(b);
newComponent.add(a);
temp.add(newComponent);
}
}
components = temp;
p.samePosition()检查节点是否具有相同的X和Y位置。我正在使用该方法而不是equals(),以防问题与等式检查失败有关,即使我没有覆盖Person类中的任何内容(包括equals(),hashCode()等)。
这似乎在大部分时间都有效。不幸的是,有时在将新连接添加到现有组件的组件之后,此代码会将新的单个组件计算为两个组件大小不正确。
我知道问题也可能是我正在计算连接错误。但是,连接在屏幕上正确显示,并且它们的数量正确(在集合中 - 不仅仅是在屏幕上计数),因此错误可能不存在。以防万一,这是计算连接的代码。它比上面的代码更不通用,所以可能更难阅读。
// "infected" and "infector" are the nodes.
// sameColor is true if the nodes have the same type.
// Nodes with the same type should retain their connections
// (which are also to nodes of the same type) while if the nodes have different types
// then the "infected" node will lose its connections because
// it will no longer be the same type as those connections.
// Note that nodes of different types should never have connections to each other.
boolean sameColor = (infected.getVirus().equalsVirus(infector.getVirus()));
boolean sameColorConnectionExists = false;
// As above, hardConnections is a set of connections between nodes (the Person class)
Iterator<Person[]> it = hardConnections.iterator();
while (it.hasNext()) {
Person[] connection = it.next();
if (sameColor) {
if ((infected.equals(connection[0]) && infector.equals(connection[1])) ||
(infected.equals(connection[1]) && infector.equals(connection[0]))) {
sameColorConnectionExists = true;
}
}
// Remove connections to the connected person.
else if (infected.equals(connection[0]) || infected.equals(connection[1])) {
it.remove();
}
}
// Create a new connection if the nodes were of different types or
// if they are the same type but no connection exists between them.
if (!sameColor || !sameColorConnectionExists) {
hardConnections.add(new Person[] {infected, infector});
}
// After this function returns, the infected node is changed to the type of the infector.
基本上发生的事情是我们遍历连接集并删除与受感染节点的任何连接,这些连接不是来自相同类型的节点。然后,如果感染节点和感染节点之间的连接不存在,我们添加一个。
我无法弄清楚这里的bug在哪里......任何帮助(甚至是项目本身的其他提示/评论)都会受到赞赏。如果您正在查看github中的代码,则有问题的代码位于Statistics.java函数updateConnections()和updateComponents()中。 updateConnections()在transferVirus()中从Person.java调用。
感谢。
更新
我一直在输出调试信息,试图弄清楚发生了什么。我已经隔离了一次导致错误碎片的碰撞。在下面的数据中,第一部分显示图的边缘,第二部分显示连接的组件以及它们中的节点数。正如您所看到的,在第二次碰撞之后,有一个额外的“深灰色”组件不应该存在。只有一个“深灰色”组件,它有4个节点。 (截图:http://screencast.com/t/f9PIzjuk)
----
blue:(489, 82) blue:(471, 449)
blue:(416, 412) blue:(471, 449)
pink:(207, 172) pink:(204, 132)
dark gray:(51, 285) dark gray:(635, 278)
dark gray:(635, 278) dark gray:(746, 369)
dark gray:(51, 285) dark gray:(737, 313)
dark gray:(737, 313) dark gray:(635, 278)
cyan:(2, 523) cyan:(473, 273)
3 blue
2 pink
4 dark gray
2 cyan
----
blue:(514, 79) blue:(535, 435)
dark gray:(725, 326) dark gray:(717, 365)
blue:(404, 404) blue:(535, 435)
pink:(197, 186) pink:(236, 127)
dark gray:(35, 283) dark gray:(619, 271)
dark gray:(619, 271) dark gray:(717, 365)
dark gray:(35, 283) dark gray:(725, 326)
dark gray:(725, 326) dark gray:(619, 271)
cyan:(1, 505) cyan:(490, 288)
3 blue
2 pink
4 dark gray
2 dark gray
2 cyan
----
在更多地考虑我需要哪些信息以便在不产生大量信息的情况下进行调试时,我在模拟过程中产生了快照的结果:
red:(227, 344) red:(257, 318)
red:(643, 244) red:(437, 140)
red:(437, 140) red:(257, 318)
orange:(573, 485) orange:(255, 143)
orange:(255, 143) orange:(20, 86)
red:(227, 344) red:(437, 140)
orange:(727, 494) orange:(573, 485)
3 red
red:(257, 318)
red:(227, 344)
red:(437, 140)
4 orange
orange:(255, 143)
orange:(573, 485)
orange:(20, 86)
orange:(727, 494)
2 red
red:(437, 140)
red:(643, 244)
如果你遵循这里的逻辑:
red:(227, 344), red:(257, 318)
创建一个新组件。red:(227, 344), red:(257, 318)
。 这是错误的,因为列表后面有其他节点将当前连接中的节点连接到原始组件。 所以现在我知道我找到连接组件的算法实际上是错误的。我想我需要对此进行一些研究。我的第一个想法是采取以下方法:
对此方法的任何想法都会受到赞赏。
答案 0 :(得分:0)
对上述OP的评论 -
对于任何感兴趣的人,我完全重新设计了算法(它基本上将一组独特的双向边缘映射到一组连接的组件[size> 2])。您可以在https://github.com/IceCreamYou/ViralSpread/blob/master/Statistics.java
的github仓库中找到它