0

TreeSet ( sortedNodes) と ArrayList ( nodes) で奇妙な問題が発生しています。私のプログラムでは、Event Dispatch Thread (from ActionListener) から呼び出されるメソッドに次の行があります。

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

問題は、一部のコレクションでsortedNodes.size()より低い数値を返すことですnodes.size()(これらの 3 行では、の内容に変更はありませんnodes)。のコンテンツを印刷するとsortedNodes、必要なすべてのオブジェクトが含まれていないだけでなく、ソートされていません。奇妙なことに、メソッド全体を再度呼び出すと、問題が修正されます。わかりません-同じコレクションで同じコードが実行されますが、最初は機能せず、2回目は機能します。何か案は?

編集:私の問題があまり明確でない場合、これが役立つはずです

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 が新しいコレクションに追加/削除され、この新しいコレクションを nodeShapes の代わりに exportTree() で使用しましたが、同じように動作するため、nodeShapes に問題はありません. それはただのTreeSetです..私がそれを使用しない場合、すべてが正常に機能します(ただし、ノードがソートされません)。

4

4 に答える 4

5

TreeSet は Set セマンティクスに従うため、重複は許可されません。ArrayList は重複を許可するため、ノードを複数回追加すると、TreeSet よりも多くのノードを持つことができます。

TreeSet は Comparable セマンティクスを使用してソートします。あなたのノードは同等ですか?Comparator を渡してソート方法を教えますか? あなたがすべき。

TreeSet は、プリミティブ、文字列、および Comparable であるその他のものに対して、ユーザー側で何の努力もせずに自然に機能します。

おそらく、それらはあなたが観察している行動のいくつかを説明しています.

于 2010-01-06T02:59:22.783 に答える
1

そして、これが私がコードを求めた理由です... :) :) :)

ノードをセットに追加した、値を出力する前に、ノードのラベルを変更している可能性があります。ラベルはセットの等価性に使用されるものです。一つには、ノードが一貫性​​のない結果を提供しているため、セットの内部動作をひどくいじっています...しかし、それは実際には問題ではありません。

私が考えているのは、ノードをセットに追加するときに、ノードが「a」、「b」、「c」などのラベルを ArrayList からすぐに提示していることです...そして、それらは「a1」を持つように修正されます。 「b1」などは後で(ただし印刷前に)ラベルを付けます。これが、ラベルがすべて「固定」されているため、2 番目の呼び出しが機能する理由です。最初の呼び出しでは、最初にセットに追加されたときに、おそらく実際には重複しています。

...より良い「制御」データを提供する以前のデバッグ ルーチンは、これを明らかにします。

明確にするために編集します。

7 つのノードの ArrayList から始めますが、そのうちの 3 つが他のノードと同じラベルを持っているため、一意のラベルは 4 つしかありません。

これらの 7 つすべてを Set に追加すると、一意のラベルが 4 つしかないため、セット内の要素は 4 つだけになります。

次に、ノードのラベルを変更します (たとえば、"b" -> "b1" を変更します)。

メソッドを再度実行すると、ラベルが既に設定されているため、すべてが機能します。

以前の「コントロール」デバッグに関するコメントは、ノードを変更する前に配列リストとセットの内容をダンプすることを提案していました...つまり、「デバッグ」の条件を変更した後ではなく、奇妙な結果が表示された直後にテスト。

于 2010-01-06T22:27:56.817 に答える
0

行の後にたくさんのコードがあります:

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

その下で行われていることは、ノードオブジェクトを変更している可能性があります。これにより、exportTree()メソッドが2回目に期待どおりに動作するようになります。可能であれば、行をコメントアウトして、2回目の呼び出しでメソッドが期待どおりに機能するかどうかを確認します。

于 2010-01-06T13:15:58.617 に答える
0

スレッドの痕跡は見当たりませんが、これは確かにスレッドの問題のように聞こえます。Synchronizedコレクションを使用して、動作が同じかどうかを確認しましたか?

于 2010-01-06T13:44:28.490 に答える