TreeSet ведет себя странно - PullRequest
       15

TreeSet ведет себя странно

0 голосов
/ 06 января 2010

У меня странная проблема с TreeSet (sortedNodes) и ArrayList (nodes). В моей программе у меня есть метод, вызванный из Thread Dispatch Thread (из ActionListener), эти строки:

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

Проблема в том, что в некоторых коллекциях sortedNodes.size() возвращает меньшее число, чем nodes.size() (в этих 3 строках, поэтому нет никаких изменений в содержании 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());
    }
}

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

Весь метод:

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 .. когда я его не использую, все работает нормально (но я не сортирую свои узлы).

Ответы [ 4 ]

5 голосов
/ 06 января 2010

TreeSet следует за Set semantics, поэтому дубликаты не допускаются. ArrayList допускает дублирование, поэтому он может иметь больше узлов, чем TreeSet, если вы добавляете узлы более одного раза.

TreeSet сортирует с использованием сопоставимой семантики. Ваш узел сопоставим? Вы передаете компаратор, чтобы сказать ему, как сортировать? Вы должны.

TreeSet работает без каких-либо усилий с вашей стороны для примитивов, строк и всего, что сопоставимо.

Возможно, они объясняют некоторые из поведения, которое вы наблюдаете.

1 голос
/ 07 января 2010

И вот почему я попросил код ... :) :):)

Вы потенциально меняете метку узла после , добавляя его в набор, но дораспечатывать значения.Метка - это то, что используется для эквивалентности множества.Во-первых, вы плохо осматриваете внутреннюю работу набора, поскольку ваши узлы дают противоречивые результаты ... но здесь проблема не в этом.

Я подозреваю, что происходит то, что узлы представляютметки типа "a", "b", "c" прямо из ArrayList при добавлении их в набор ... и затем они исправляются, чтобы впоследствии иметь метки "a1", "b1" и т. д. (но допечать).Вот почему второй вызов работает, потому что все метки были «исправлены».При первом вызове они, вероятно, действительно являются дубликатами при первом добавлении в набор.

... более ранние процедуры отладки, которые предоставляют более качественные «контрольные» данные, выявят это.

Редактироватьуточнить:

Вы начинаете с ArrayList из семи узлов, но 3 из них имеют такую ​​же метку, как некоторые другие, так что есть только 4 уникальные метки.

Вы добавляете все 7 издля набора и получают только 4 элемента в наборе, потому что было только 4 уникальных метки.

Затем вы изменяете метки узлов (например, изменяя "b" -> "b1").

При повторном запуске метода все работает, потому что метки уже настроены.

Комментарий о более ранней «контрольной» отладке был предложением сбросить содержимое списка массива и заданного ранее значения.модифицировать узлы ... то есть: сразу после того, как вы видите странные результаты, а не после изменения условий "отладочного" тестирования.

0 голосов
/ 06 января 2010

Несмотря на то, что я не вижу следов потоков, это действительно звучит для меня как вопрос потоков. Вы пытались использовать синхронизированную коллекцию для проверки того же поведения?

0 голосов
/ 06 января 2010

У вас много кода после вашей строки:

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

Что-то, что сделано под ним, может изменить объект вашего узла, что заставит метод exportTree () вести себя так, как ожидалось во второй раз. Если можете, закомментируйте строки и посмотрите, работает ли ваш метод так, как ожидалось при втором вызове.

...