2009-08-31 13 views
36

Kennt jemand eine generische Struktur (Knoten können mehrere untergeordnete Elemente haben) Implementierung für Java? Es sollte von einer vertrauenswürdigen Quelle stammen und vollständig getestet werden.Generische Baumimplementierung in Java

Es scheint einfach nicht richtig, es selbst zu implementieren. Fast erinnert mich an meine Universitätsjahre, als wir alle unsere Sammlungen selbst schreiben sollten.

EDIT: Gefunden this project auf java.net, könnte einen Blick wert sein.

+1

Wie möchten Sie diesen Baum verwenden? – pjp

+0

, d. H. Definieren Sie die Struktur selbst (wie ein Familienstammbaum) oder sind die Elemente vergleichbar und möchten Sie sie effizient in den Baum einfügen? – pjp

+0

Jeder Knoten sollte in der Lage sein, eine Liste von Kindern in der Reihenfolge des Einfügens zu führen. Ich muss etwas wie * postorder * traversal (http://en.wikipedia.org/wiki/Tree_traversal) tun, die Kinder eines Knotens in umgekehrter Richtung durchquert. –

Antwort

23

Hier kommt es:

abstract class TreeNode implements Iterable<TreeNode> { 

    private Set<TreeNode> children; 

    public TreeNode() { 
    children = new HashSet<TreeNode>(); 
    } 

    public boolean addChild(TreeNode n) { 
    return children.add(n); 
    } 

    public boolean removeChild(TreeNode n) { 
    return children.remove(n); 
    } 

    public Iterator<TreeNode> iterator() { 
    return children.iterator(); 
    } 
} 

Ich bin gut vertraut, aber haben die Umsetzung nicht getestet.

+0

einfach überprüfen dass TreeNode equals und hashCode ordnungsgemäß implementiert. – pjp

+1

Danke, aber ich brauche etwas gut getestet, sonst müsste ich ein paar Stunden damit verbringen Komponententests davon zu schreiben ... –

+0

Wie erreichst du genau die Kinder von TreeNode? : P –

9

Es gibt keine Tree-Klasse in den Collections-Bibliotheken. Allerdings ist dort eins in den Swing Frameworks. DefaultTreeModel

Ich habe dies in der Vergangenheit verwendet und es funktioniert gut. Es zieht zusätzliche Klassen in Ihre Anwendung, obwohl dies wünschenswert sein kann oder nicht.

können Sie simulieren auch ein Baum eine weitere Sammlung und Speicherung von Sammlungen in der Benutzung. Z.B. Liste der Listen.

+0

Danke für die Idee, ich werde es versuchen. Schnittstellen sehen zumindest ziemlich brauchbar aus: javax.swing.tree.TreeNode. –

+3

Ich kann nicht verstehen, warum dies nicht in der Standard-Sammlung API ist. – Fortyrunner

+0

Meine Vermutung ist, dass es sich nicht in der Sammlungs-API befindet, da es den bereits verfügbaren Sammlungsimplementierungen keine zusätzlichen Elemente hinzufügt. – Zed

0

Ich verwende einen XML-DOM (XML beschreibt eine Baumstruktur) und speziell auf den Open-Source-XOM (http://www.xom.nu). Dies ist leichtgewichtig, Knoten können bei Bedarf unterklassifiziert und sehr stark verwendet und getestet werden. Es kann größer sein, als Sie benötigen, aber es hat den Vorteil, dass alle Baumnavigationsmethoden (Vorfahren, Geschwister usw.) vollständig über XPath verwaltet werden. Sie können den Baum auch serialisieren und mit getesteten XML-Methoden umwandeln. Es gibt auch eine starke Nutzergemeinschaft

+7

XML ist nett und alles, aber wie kann man das Wort "leicht" damit verwenden? – Karl

6

Ah, ich wollte eine schamlose Werbung meiner Lösung schreiben und sah, dass jemand bereits einen Link darauf geschrieben. Ja, ich hatte das gleiche Problem und habe letztendlich meinen eigenen Generic Tree geschrieben. Ich habe Tests für den Baumknoten und den Baum selbst.

I implementiert, um den Knoten als ein Objekt ein Datenfeld und eine Liste von Knoten (die die Kinder dieses Knotens sind).

http://vivin.net/2010/01/30/generic-n-ary-tree-in-java/

2

fand ich eine absolut fantastische Bibliothek http://jung.sourceforge.net, http://jung.sourceforge.net/doc/api/index.html die javadoc sehen. Es ist viel mehr als nur eine Graphimplementierung. Mit ihm können Sie Graphen visualisieren und gestalten; Außerdem verfügt es über eine Reihe von Standard-Grafikalgorithmen, die Sie sofort verwenden können. Los, schau es dir an! Obwohl ich letztendlich meinen eigenen Basisgraphen implementiert habe (ich kannte JUNG vorher nicht), verwende ich diese Bibliothek zur Visualisierung. Es sieht sehr ordentlich aus!

8

Es ist ziemlich schwierig, eine echte generische Baumimplementierung in Java zu machen, die die Baumoperationen und Eigenschaften von den zugrunde liegenden Implementierungen wirklich trennt, dh einen RedBlackTreeNode eintauscht und einige Methoden außer Kraft setzt, um eine RedBlackTree-Implementierung zu erhalten, während alle generischen beibehalten werden Operationen, die eine BinaryTree-Schnittstelle enthält.

Auch wäre eine ideale Abstraktion in der Lage, die Low-Level-Baumdarstellung, z. eine implizite binäre Baumstruktur, die in einem Array für eine Heap- oder Node-Base-Schnittstelle mit linken und rechten Child-Pointern oder mehreren Child-Pointern gespeichert ist, oder eine der oben genannten Funktionen mit Parent-Zeigern oder Threading der Blattknoten usw. usw., usw.

Ich habe versucht, dies selbst zu lösen, aber endete mit einer ziemlich komplizierten Schnittstelle, die immer noch Typsicherheit erzwingt. Hier ist das Grundgerüst der Idee, die eine abstrakte BinaryTree-Klasse mit einer nicht-trivialen Operation (Euler-Tour) erstellt, die auch dann funktioniert, wenn die zugrunde liegende Knotenklasse oder Baumklasse geändert wird. Es könnte wahrscheinlich verbessert werden, indem die Idee der Cursor für die Navigation und Positionen innerhalb der Baumstruktur Einführung:

public interface Tree<E, P extends Tree.Entry<E, P>> extends Collection<E> 
{ 
    public P getRoot(); 
    public Collection<P> children(P v); 
    public E getValue(P v); 

    public static interface Entry<T, Q extends Entry<T, Q>> { } 
} 

public interface BinaryTree<E, P extends BinaryTree.Entry<E, P>> extends Tree<E, P> 
{ 
    public P leftChild(P v); 
    public P rightChild(P v); 

    public static interface Entry<T, Q extends Entry<T, Q>> extends Tree.Entry<T, Q> 
    { 
     public Q getLeft(); 
     public Q getRight(); 
    } 
} 

public interface TreeTraversalVisitor<E, P extends BinaryTree.Entry<E, P>, R> 
{ 
    public R visitLeft(BinaryTree<E, P> tree, P v, R result); 
    public R visitCenter(BinaryTree<E, P> tree, P v, R result); 
    public R visitRight(BinaryTree<E, P> tree, P v, R result); 
} 

public abstract class AbstractBinaryTree<E, P extends BinaryTree.Entry<E, P>> extends AbstractCollection<E> implements BinaryTree<E, P> 
{ 
    public Collection<P> children(P v) 
    { 
     Collection<P> c = new ArrayList<P>(2); 

     if (hasLeft(v)) 
     c.add(v.getLeft()); 

     if (hasRight(v)) 
     c.add(v.getRight()); 

     return c; 
    } 

    /** 
    * Performs an Euler Tour of the binary tree 
    */ 
    public static <R, E, P extends BinaryTree.Entry<E, P>> 
    R eulerTour(BinaryTree<E, P> tree, P v, TreeTraversalVisitor<E, P, R> visitor, R result) 
    { 
     if (v == null) 
     return result; 

     result = visitor.visitLeft(tree, v, result); 

     if (tree.hasLeft(v)) 
     result = eulerTour(tree, tree.leftChild(v), visitor, result); 

     result = visitor.visitCenter(tree, v, result); 

     if (tree.hasRight(v)) 
     result = eulerTour(tree, tree.rightChild(v), visitor, result); 

     result = visitor.visitRight(tree, v, result); 

     return result; 
    }  
} 
10

Verwenden Guava

Guava15.0 führt eine schöne API für Baumdurchlauf, so dass Sie nicht wieder müssen - Implementieren Sie es zum gilliillionsten Mal in Ihrer Codebasis.

Nämlich, TreeTraverser und einige spezialisierte Implementierungen, wie BinaryTreeTraverser.

Ein sehr begrüßen addition Neuimplementierung etwas so einfach und mit zusätzlichen Bonus zu vermeiden:

  • mit Ruhe (Stabilität, unterstützt Bibliothek, etc ...),
  • gutes Design,
  • mehrere Traversierungsmodi eingebaut.

während man dort ...

Beachten Sie, dass Guava auch jetzt neue Methoden zu seiner Files Utility-Klasse bietet die Verwendung des TreeTraverser machen, z.B. Files.fileTreeTraverser(), die Ihnen eine TreeTraverser<File> für Ihre Dateisystem-Traversal Bedürfnisse gibt.

+1

Aber es ist eine abstrakte Klasse, keine vollständige Implementierung. –

+1

@quant_dev: Ja, aber es bringt dir 95% des Weges, deine konkrete typsichere Klasse zu schreiben, anstatt eine generische Klasse zu benutzen, die nicht gut zu dir passt. Es gibt mehrere Möglichkeiten, das zu tun, das ist sicher. Ich war nur überrascht, dass niemand das erwähnt hat. Wenn Sie eine konkrete Implementierung wünschen, dann ist das Swing DefaultTreeModel dafür ziemlich nützlich. – haylem