[英]TreeSet acting weird
我在TreeSet( sortedNodes
)和ArrayList( nodes
)上遇到了一个奇怪的问题。 在我的程序中,我有一个从事件调度线程(从ActionListener
)调用的方法,这些行:
System.out.println("nodes: "+nodes.size());
sortedNodes.addAll(nodes);
System.out.println("sortedNodes: "+sortedNodes.size());
问题是,在某些集合上, sortedNodes.size()
返回的数字比nodes.size()
(在这三行中, nodes
内容没有变化)。 然后,当我打印sortedNodes
内容时,除了不包含它应该包含的所有对象外,它甚至没有被排序。 奇怪的是-如果我再次调用整个方法,它将解决此问题。 我不明白-在相同的集合上执行相同的代码,但是第一次不起作用,第二次却不起作用。 有任何想法吗?
编辑:如果我的问题不是很清楚,这应该有所帮助
exportTree();
exportTree();
放在输出上:
nodes: 7
sortedNodes: 4
b2[23,57]a[46,97]b[65,77]c[43,43]
nodes: 7
sortedNodes: 7
a[46,97]b[65,77]b1[55,89]b2[23,57]b3[20,20]c[43,43]c1[99,88]
比较器:
public class NodeComparator implements Comparator<Node>{
public int compare(Node o1, Node o2) {
return o1.getLabel().compareTo(o2.getLabel());
}
}
节点:
public class Node {
private int order;
private String label;
private Integer[] keys;
private Node[] pointers;
private Node parent;
public Node(int order, String label, Integer[] keys, Node[] pointers) {
this.order = order;
this.label = label;
this.parent = null;
if (pointers == null) {
this.pointers = new Node[order+1];
} else {
this.pointers = pointers;
}
if (keys == null) {
this.keys = new Integer[order];
} else {
this.keys = keys;
}
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public Integer[] getKeys() {
return keys;
}
public void setKeys(Integer[] keys) {
this.keys = keys;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public Node[] getPointers() {
return pointers;
}
public void setPointers(Node[] pointers) {
this.pointers = pointers;
}
public Node getPointer(int i) {
return pointers[i];
}
public void setPointer(int i, Node node) {
pointers[i] = node;
}
public Integer getKey(int i) {
return keys[i];
}
public void setKey(int i, Integer key) {
keys[i] = key;
}
}
整个方法:
public void exportTree() {
String graphInText = "";
if (nodeShapes.isEmpty()) {
graphInText = "empty";
} else {
char c = 'a';
ArrayList<Node> nodes = new ArrayList<Node>();
sortedNodes.clear();
System.out.println("nodeShapes: " + nodeShapes.size());
// populate the collection of nodes from their 2d representation(nodeShapes)
// and label every root with different character
for (NodeShape n : nodeShapes) {
nodes.add(n.getNode());
if (n.getParentLink() == null) {
n.getNode().setLabel(c + "");
c++;
}
}
System.out.println("nodes: " + nodes.size());
// copy all the nodes (currently every node except roots has label "0")
sortedNodes.addAll(nodes);
System.out.println("sortedNodes: " + sortedNodes.size());
// check labels of every node; if it contains any of the characters
// that were assigned to roots, use this label for every child of
// this node and add number of the pointer at the end of the string;
// when this is done, remove those nodes, which children have been
// labeled;
// repeat whole procedure while there is no node left - and this will
// happen, since every node is connected to a root or is a root;
while (!nodes.isEmpty()) {
ArrayList<Node> nodesToBeRemoved = new ArrayList<Node>();
for (Node n : nodes) {
for (char c2 = 'a'; c2 <= c; c2++) {
if (n.getLabel().contains(c2 + "")) {
for (int i = 1; i <= n.getOrder(); i++) {
Node child = n.getPointer(i);
if (child != null) {
child.setLabel(n.getLabel() + i);
}
}
nodesToBeRemoved.add(n);
}
}
}
if (!nodesToBeRemoved.isEmpty()) {
nodes.removeAll(nodesToBeRemoved);
}
}
Node[] nodesA = sortedNodes.toArray(new Node[sortedNodes.size()]);
for (Node n : nodesA) {
String nodeInText;
nodeInText = n.getLabel() + "[";
for (int i = 1; i < n.getOrder() - 1; i++) {
nodeInText += n.getKey(i) + ",";
}
nodeInText += n.getKey(n.getOrder() - 1) + "]";
graphInText += nodeInText;
}
}
System.out.println(graphInText);
label.setText(graphInText);
}
我还更改了程序,因此每次创建/删除NodeShape时,也会将Node添加/删除到新集合中,并且我在exportTree()中使用了这个新集合而不是nodeShapes-但它的工作原理相同,因此nodeShapes没问题。 它只是TreeSet ..当我不使用它时,一切正常(但是我没有对节点进行排序)。
TreeSet遵循Set语义,因此不允许重复。 ArrayList确实允许重复,因此如果您多次添加Node,则它可能比TreeSet具有更多的节点。
TreeSet使用可比语义进行排序。 您的节点可比吗? 您是否通过比较器来告诉它如何排序? 你应该。
TreeSet可以自然工作,而无需您费力地处理原语,字符串以及任何其他可比较的东西。
也许这些解释了您正在观察的某些行为。
这就是为什么我要求输入代码的原因... :) :) :)
将其添加到组之后 ,但打印出来的值之前可能改变节点的标签。 标签是用于设置等效项的标签。 一方面,由于您的节点提供的结果不一致,因此您很难考虑该集合的内部工作原理……但这并不是真正的问题。
我怀疑正在发生的事情是,当节点将它们添加到集合中时,它们会在ArrayList中显示诸如“ a”,“ b”,“ c”之类的标签,然后对其进行校正以使其具有“ a1”,之后(但在打印之前)使用“ b1”等标签。 这就是第二个调用起作用的原因,因为标签都已“固定”。 在第一次调用中,它们可能真的是第一次将它们添加到集合中时的重复项。
...提供更佳“控制”数据的早期调试例程将揭示这一点。
编辑以澄清:
您从具有七个节点的ArrayList开始,但是其中三个节点与其他一些节点具有相同的标签,因此只有4个唯一标签。
您将所有7个元素添加到集合中,因为只有4个唯一标签,所以在集合中仅获得4个元素。
然后,您修改节点的标签(例如,更改“ b”->“ b1”)。
当您再次运行该方法时,由于标签已经设置好,因此一切正常。
关于早期“控制”调试的评论是建议在修改节点之前转储数组列表和集合的内容……即:在看到奇怪的结果之后,而不是在更改“调试”的条件之后测试。
您的代码行之后有很多代码:
System.out.println("sortedNodes: " + sortedNodes.size());
在它下面进行的某些操作可能是修改您的nodes对象,这导致exportTree()方法第二次表现出预期的效果。 如果可以,请注释掉这些行,然后查看您的方法是否在第二次调用中按预期工作。
即使我看不到线程的痕迹,对我来说,这的确听起来像是线程问题。 您是否尝试过使用同步集合检查行为是否相同?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.