简体   繁体   English

TreeSet代理很奇怪

[英]TreeSet acting weird

I'm having a weird problem with TreeSet ( sortedNodes ) and ArrayList ( nodes ). 我在TreeSet( sortedNodes )和ArrayList( nodes )上遇到了一个奇怪的问题。 In my program, I have in a method called from Event Dispatch Thread (from ActionListener ) these lines: 在我的程序中,我有一个从事件调度线程(从ActionListener )调用的方法,这些行:

        System.out.println("nodes: "+nodes.size());
        sortedNodes.addAll(nodes);
        System.out.println("sortedNodes: "+sortedNodes.size());

Problem is, on some collections sortedNodes.size() returns lower number than nodes.size() (on these 3 lines, so there is no change in content of nodes ). 问题是,在某些集合上, sortedNodes.size()返回的数字比nodes.size() (在这三行中, nodes内容没有变化)。 When I then print content of sortedNodes , it's not even sorted in addition to not containing all the objects it should. 然后,当我打印sortedNodes内容时,除了不包含它应该包含的所有对象外,它甚至没有被排序。 Weird thing is - if I call the whole method again, it fixes the issue. 奇怪的是-如果我再次调用整个方法,它将解决此问题。 I don't get it - same code is executed, on same collections, but first time it doesn't work and 2nd time it does. 我不明白-在相同的集合上执行相同的代码,但是第一次不起作用,第二次却不起作用。 Any ideas? 有任何想法吗?

EDIT: If my problem is not very clear, this should help 编辑:如果我的问题不是很清楚,这应该有所帮助

exportTree();
exportTree();

pritns on output this: 放在输出上:

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]

Comparator: 比较器:

public class NodeComparator implements Comparator<Node>{
    public int compare(Node o1, Node o2) {
        return o1.getLabel().compareTo(o2.getLabel());
    }
}

Node: 节点:

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;
}
}

Whole method: 整个方法:

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);
}

I also altered the program so every time I create/remove NodeShape, also Node is added/removed to new collection and I used this new collection in exportTree() instead of nodeShapes - but it works the same, so there is no problem with nodeShapes. 我还更改了程序,因此每次创建/删除NodeShape时,也会将Node添加/删除到新集合中,并且我在exportTree()中使用了这个新集合而不是nodeShapes-但它的工作原理相同,因此nodeShapes没问题。 It's just the TreeSet.. when I don't use it, everything works okay (but I don't get my nodes sorted). 它只是TreeSet ..当我不使用它时,一切正常(但是我没有对节点进行排序)。

TreeSet follows Set semantics, so no duplicates are allowed. TreeSet遵循Set语义,因此不允许重复。 ArrayList does allow duplicates, so it could have more nodes than TreeSet if you add Nodes more than once. ArrayList确实允许重复,因此如果您多次添加Node,则它可能比TreeSet具有更多的节点。

TreeSet sorts using Comparable semantics. TreeSet使用可比语义进行排序。 Is your Node Comparable? 您的节点可比吗? Do you pass a Comparator to tell it how to sort? 您是否通过比较器来告诉它如何排序? You should. 你应该。

TreeSet works naturally without any effort on your part for primitives, Strings, and anything else that is Comparable. TreeSet可以自然工作,而无需您费力地处理原语,字符串以及任何其他可比较的东西。

Perhaps those explain some of the behavior you're observing. 也许这些解释了您正在观察的某些行为。

And this is why I asked for the code... :) :) :) 这就是为什么我要求输入代码的原因... :) :) :)

You are potentially changing the label of the node after adding it to the set but before printing out the values. 将其添加到组之后 ,但打印出来的值之前可能改变节点的标签。 The label is what is used for set equivalence. 标签是用于设置等效项的标签。 For one thing, you are badly mucking around the internal workings of the set since your nodes are providing inconsistent results... but that's not really the problem here. 一方面,由于您的节点提供的结果不一致,因此您很难考虑该集合的内部工作原理……但这并不是真正的问题。

What I suspect is happening is that the nodes are presenting labels like "a", "b", "c" right out of the ArrayList when adding them to the set... and then they are corrected to have their "a1", "b1", etc. labels afterwards (but before printing). 我怀疑正在发生的事情是,当节点将它们添加到集合中时,它们会在ArrayList中显示诸如“ a”,“ b”,“ c”之类的标签,然后对其进行校正以使其具有“ a1”,之后(但在打印之前)使用“ b1”等标签。 This is why the second call works because the labels have all been "fixed". 这就是第二个调用起作用的原因,因为标签都已“固定”。 In the first call, they probably really are duplicates the first time they are added to the set. 在第一次调用中,它们可能真的是第一次将它们添加到集合中时的重复项。

...earlier debugging routines that provide better "control" data would reveal this. ...提供更佳“控制”数据的早期调试例程将揭示这一点。

Edit to clarify: 编辑以澄清:

You start with an ArrayList of seven nodes but 3 of them have the same label as some of the others so that there are only 4 unique labels. 您从具有七个节点的ArrayList开始,但是其中三个节点与其他一些节点具有相同的标签,因此只有4个唯一标签。

You add all 7 of those to a Set and only get 4 elements in the set because there were only 4 unique labels. 您将所有7个元素添加到集合中,因为只有4个唯一标签,所以在集合中仅获得4个元素。

You then modify the labels of the nodes (for example changing "b" -> "b1"). 然后,您修改节点的标签(例如,更改“ b”->“ b1”)。

When you run the method again then everything works because the labels have already been setup. 当您再次运行该方法时,由于标签已经设置好,因此一切正常。

The comment about earlier "control" debugging was a suggestion to dump the contents of the array list and the set prior to modifying the nodes... ie: right after you see your strange results and not after altering the conditions of the "debug" testing. 关于早期“控制”调试的评论是建议在修改节点之前转储数组列表和集合的内容……即:在看到奇怪的结果之后,而不是在更改“调试”的条件之后测试。

You've got a lot of code after your line: 您的代码行之后有很多代码:

System.out.println("sortedNodes: " + sortedNodes.size());

Something that's done beneath it may could be modifying your nodes object which causes the exportTree() method to behave as expected the second time around. 在它下面进行的某些操作可能是修改您的nodes对象,这导致exportTree()方法第二次表现出预期的效果。 If you can, comment out the lines and see if your method works as expected on the second call. 如果可以,请注释掉这些行,然后查看您的方法是否在第二次调用中按预期工作。

Even though I see no traces of threading, this indeed sounds like a threading issue to me. 即使我看不到线程的痕迹,对我来说,这的确听起来像是线程问题。 Did you try using a Synchronized collection to check if the behaviour is the same? 您是否尝试过使用同步集合检查行为是否相同?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM