2010-11-15 14 views
5

¿Cuál es la forma más fácil de imprimir un árbol en su estructura de árbol? Tales como ...¿Cómo se puede imprimir un árbol de una forma muy bien formateada?

    some root 
      / |   \ 
      child1 child2  child 3 
     /
     anotherchild    /\ 
          yup  another 

Incluso formatearlo a mano es difícil. ¿Cómo se puede hacer que un programa imprima un árbol de esta manera?

+0

debe cambiar la etiqueta independiente del idioma, ya que hay lenguajes/entornos en los que esto se implementa de forma nativa. –

Respuesta

0

Bueno, se podría intentar algo así como var_dump de PHP - si se intenta var_dump en una matriz en forma de árbol, se le dará una representación razonable de ese árbol, es decir:

root { 
    child1 { 
     anotherchild 
    } 
    child2 
    child3 { 
     yup 
     another 
    } 
} 
5

A menos que haya una bonita librería gráfica que pueda usar, tendrá muchos problemas para representar una jerarquía en la forma que usted describe.

Suponiendo que desea imprimirlo en la consola, o un archivo, tendrá que lidiar con el cálculo previo de las longitudes de todos los elementos de datos en todo el árbol para alinearlos correctamente. ¿Y cómo manejas cosas como line-wrap?

Una forma mucho mejor es representar el árbol verticalmente, usando la sangría para mostrar un elemento secundario.

Root 
    - Child1 
     - Grandchild1 
     - Grandchild2 
    - Child2 
     - Grandchild3 
     - Grandchild4 

Esto es mucho más fácil de código, y más tolerantes con cosas como linewrap - ya que sólo hay siempre un elemento en una línea. Así es como un folder-browser o un documento xml podría mostrar sus datos jerárquicos.

hacerlo de esta manera, se hace un recorrido en profundidad y antes de la etapa recursiva que imprima el nodo:

public void PrintNode(TreeNode node) 
{ 
    PrintNode(node, 0); 
} 

private void PrintNode(TreeNode node, int indentation) 
{ 
    // Print the value to the console/file/whatever 
    // This prefixes the value with the necessary amount of indentation 
    Print(node.Value, indentation); 

    // Recursively call the child nodes. 
    foreach(TreeNode childNode in node.Children) 
    { 
     PrintNode(childNode, indentation + 1); // Increment the indentation counter. 
    } 
} 

Espero que ayude

+1

Seguramente pasaría la profundidad de sangría como segundo argumento a 'PrintNode' (valor predeterminado a 0 para llamadas de cliente y agregando un nivel en la llamada recursiva)? Entonces no tendrías que disminuirlo manualmente. – Zecc

+0

Esto no es útil para imprimir un árbol en el formato solicitado. –

+0

@Zecc - Eso es lo que quise decir con la última frase (después de mi ejemplo). Intentaba escribirlo de una manera independiente del idioma sin especificar cómo se realizaba la sangría o la impresión. En realidad, normalmente recibo una llamada pública que pide una anulación privada con el 0 para ocultar eso al consumidor. – sheikhjabootie

0

¿Qué tal this answer a una pregunta similar? Imprime un buen árbol de arte ASCII.

O tal vez this one si quieres ir completamente gráfica?

0

Tuve que hacer esto el año pasado escribiendo una aplicación de árbol genealógico. Encontré un tutorial en línea de Java que ayudó, pero mi Google-fu me falló hoy, así que tendré que explicarlo simplemente.

Es simplemente un algoritmo recursivo que ajusta la posición del nodo primario en base a nodos secundarios. En pseudocódigo es algo como esto:

positionNode (node,x,y) { 
    foreach (child in node.children) { 
     positionNode(child,x,y+1) 
     x ++ 
    } 
    node.x = (x-1)/2 
    node.y = y 
} 

yo no sea recordando esto correctamente, es posible que tenga que modificar el código un poco para hacerlo bien.

0

La siguiente respuesta está en java, pero es tan simple que fácilmente puede ser transcrito a otros idiomas:

public interface Function1<R, T1> 
{ 
    R invoke(T1 argument1); 
} 

public interface Procedure1<T1> 
{ 
    void invoke(T1 argument1); 
} 

public static <T> void dump(T node, Function1<List<T>,T> breeder, 
     Function1<String,T> stringizer, Procedure1<String> emitter) 
{ 
    emitter.invoke(stringizer.invoke(node)); 
    dumpRecursive(node, "", breeder, stringizer, emitter); 
} 

private static final String[][] PREFIXES = { { " ├─ ", " │ " }, { " └─ ", " " } }; 

private static <T> void dumpRecursive(T node, String parentPrefix, 
     Function1<List<T>,T> breeder, Function1<String,T> stringizer, 
     Procedure1<String> emitter) 
{ 
    for(Iterator<T> iterator = breeder.invoke(node).iterator(); iterator.hasNext();) 
    { 
     T childNode = iterator.next(); 
     String[] prefixes = PREFIXES[iterator.hasNext()? 0 : 1]; 
     emitter.invoke(parentPrefix + prefixes[0] + stringizer.invoke(childNode)); 
     dumpRecursive(childNode, parentPrefix + prefixes[1], breeder, stringizer, emitter); 
    } 
} 

Se produce el siguiente resultado:

Automobile 
├─ Passenger Vehicle 
│ ├─ Light Passenger Vehicle 
│ │ ├─ Two Wheeled 
│ │ │ ├─ Moped 
│ │ │ ├─ Scooter 
│ │ │ └─ Motorcycle 
│ │ ├─ Three Wheeled 
│ │ └─ Four Wheeled 
│ │  ├─ Car 
│ │  ├─ Station Wagon 
│ │  ├─ Pick-up Truck 
│ │  └─ Sports Utility Vehicle 
│ └─ Heavy Passenger Vehicle 
│  ├─ Bus 
│  │ ├─ Single-Deck Bus 
│  │ │ ├─ Mini Bus 
│  │ │ └─ Big Bus 
│  │ └─ Double-Deck Bus 
│  └─ Coach 
│   ├─ Deluxe 
│   └─ Air-Conditioned 
└─ Goods Vehicle 
    ├─ Light Goods Vehicle 
    │ ├─ Delivery Van 
    │ ├─ Light Truck 
    │ └─ Tempo 
    │  ├─ Three Wheeler Tempo 
    │  └─ Four Wheeler Tempo 
    └─ Heavy Goods Vehicle 
     ├─ Truck 
     └─ Tractor Trailer 

...si se invoca utilizando el siguiente programa de ejemplo:

final class Scratch 
{ 
    static class Node 
    { 
     String name; 
     List<Node> children; 

     Node(String name, Node... children) 
     { 
      this.name = name; 
      this.children = Arrays.asList(children); 
     } 
    } 

    public static void main(String[] args) 
    { 
     Node tree = new Node("Automobile", 
       new Node("Passenger Vehicle", 
         new Node("Light Passenger Vehicle", 
           new Node("Two Wheeled", 
             new Node("Moped"), 
             new Node("Scooter"), 
             new Node("Motorcycle")), 
           new Node("Three Wheeled"), 
           new Node("Four Wheeled", 
             new Node("Car"), 
             new Node("Station Wagon"), 
             new Node("Pick-up Truck"), 
             new Node("Sports Utility Vehicle"))), 
         new Node("Heavy Passenger Vehicle", 
           new Node("Bus", 
             new Node("Single-Deck Bus", 
               new Node("Mini Bus"), 
               new Node("Big Bus")), 
             new Node("Double-Deck Bus")), 
           new Node("Coach", 
             new Node("Deluxe"), 
             new Node("Air-Conditioned")))), 
       new Node("Goods Vehicle", 
         new Node("Light Goods Vehicle", 
           new Node("Delivery Van"), 
           new Node("Light Truck"), 
           new Node("Tempo", 
             new Node("Three Wheeler Tempo"), 
             new Node("Four Wheeler Tempo"))), 
         new Node("Heavy Goods Vehicle", 
           new Node("Truck"), 
           new Node("Tractor Trailer")))); 
     dump(tree, n -> n.children, n -> n.name, s -> System.out.println(s)); 
    } 
} 
Cuestiones relacionadas