¿Cómo imprimir un diagrama de árbol binario?

163

¿Cómo puedo imprimir un árbol binario en Java para que la salida sea así:

   4 
  / \ 
 2   5 

Mi nodo:

public class Node<A extends Comparable> {
    Node<A> left, right;
    A data;

    public Node(A data){
        this.data = data;
    }
}
Tian
fuente
55
Eso es complicado. Creo que primero debes determinar la profundidad del árbol. Personalmente, simplemente volcaría el gráfico de nodo en graphviz y dejaría que se ocupe de él. :-)
Omnifarious
Parece que si tuviera muchos elementos, el elemento raíz tendría un ENORME borde proveniente de él.
Tengo un método getDept () en el árbol
Tian
1
Solo porque la idea me divirtió, escribí el código en C ++ y lo hice escupir en formato de gráfico gráfico. Árboles bellamente formateados.
Omnifarioso
vanya.jp.net/vtree
humble_wolf

Respuestas:

238

He creado una impresora de árbol binario simple. Puede usarlo y modificarlo como desee, pero de todos modos no está optimizado. Creo que muchas cosas se pueden mejorar aquí;)

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BTreePrinterTest {

    private static Node<Integer> test1() {
        Node<Integer> root = new Node<Integer>(2);
        Node<Integer> n11 = new Node<Integer>(7);
        Node<Integer> n12 = new Node<Integer>(5);
        Node<Integer> n21 = new Node<Integer>(2);
        Node<Integer> n22 = new Node<Integer>(6);
        Node<Integer> n23 = new Node<Integer>(3);
        Node<Integer> n24 = new Node<Integer>(6);
        Node<Integer> n31 = new Node<Integer>(5);
        Node<Integer> n32 = new Node<Integer>(8);
        Node<Integer> n33 = new Node<Integer>(4);
        Node<Integer> n34 = new Node<Integer>(5);
        Node<Integer> n35 = new Node<Integer>(8);
        Node<Integer> n36 = new Node<Integer>(4);
        Node<Integer> n37 = new Node<Integer>(5);
        Node<Integer> n38 = new Node<Integer>(8);

        root.left = n11;
        root.right = n12;

        n11.left = n21;
        n11.right = n22;
        n12.left = n23;
        n12.right = n24;

        n21.left = n31;
        n21.right = n32;
        n22.left = n33;
        n22.right = n34;
        n23.left = n35;
        n23.right = n36;
        n24.left = n37;
        n24.right = n38;

        return root;
    }

    private static Node<Integer> test2() {
        Node<Integer> root = new Node<Integer>(2);
        Node<Integer> n11 = new Node<Integer>(7);
        Node<Integer> n12 = new Node<Integer>(5);
        Node<Integer> n21 = new Node<Integer>(2);
        Node<Integer> n22 = new Node<Integer>(6);
        Node<Integer> n23 = new Node<Integer>(9);
        Node<Integer> n31 = new Node<Integer>(5);
        Node<Integer> n32 = new Node<Integer>(8);
        Node<Integer> n33 = new Node<Integer>(4);

        root.left = n11;
        root.right = n12;

        n11.left = n21;
        n11.right = n22;

        n12.right = n23;
        n22.left = n31;
        n22.right = n32;

        n23.left = n33;

        return root;
    }

    public static void main(String[] args) {

        BTreePrinter.printNode(test1());
        BTreePrinter.printNode(test2());

    }
}

class Node<T extends Comparable<?>> {
    Node<T> left, right;
    T data;

    public Node(T data) {
        this.data = data;
    }
}

class BTreePrinter {

    public static <T extends Comparable<?>> void printNode(Node<T> root) {
        int maxLevel = BTreePrinter.maxLevel(root);

        printNodeInternal(Collections.singletonList(root), 1, maxLevel);
    }

    private static <T extends Comparable<?>> void printNodeInternal(List<Node<T>> nodes, int level, int maxLevel) {
        if (nodes.isEmpty() || BTreePrinter.isAllElementsNull(nodes))
            return;

        int floor = maxLevel - level;
        int endgeLines = (int) Math.pow(2, (Math.max(floor - 1, 0)));
        int firstSpaces = (int) Math.pow(2, (floor)) - 1;
        int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1;

        BTreePrinter.printWhitespaces(firstSpaces);

        List<Node<T>> newNodes = new ArrayList<Node<T>>();
        for (Node<T> node : nodes) {
            if (node != null) {
                System.out.print(node.data);
                newNodes.add(node.left);
                newNodes.add(node.right);
            } else {
                newNodes.add(null);
                newNodes.add(null);
                System.out.print(" ");
            }

            BTreePrinter.printWhitespaces(betweenSpaces);
        }
        System.out.println("");

        for (int i = 1; i <= endgeLines; i++) {
            for (int j = 0; j < nodes.size(); j++) {
                BTreePrinter.printWhitespaces(firstSpaces - i);
                if (nodes.get(j) == null) {
                    BTreePrinter.printWhitespaces(endgeLines + endgeLines + i + 1);
                    continue;
                }

                if (nodes.get(j).left != null)
                    System.out.print("/");
                else
                    BTreePrinter.printWhitespaces(1);

                BTreePrinter.printWhitespaces(i + i - 1);

                if (nodes.get(j).right != null)
                    System.out.print("\\");
                else
                    BTreePrinter.printWhitespaces(1);

                BTreePrinter.printWhitespaces(endgeLines + endgeLines - i);
            }

            System.out.println("");
        }

        printNodeInternal(newNodes, level + 1, maxLevel);
    }

    private static void printWhitespaces(int count) {
        for (int i = 0; i < count; i++)
            System.out.print(" ");
    }

    private static <T extends Comparable<?>> int maxLevel(Node<T> node) {
        if (node == null)
            return 0;

        return Math.max(BTreePrinter.maxLevel(node.left), BTreePrinter.maxLevel(node.right)) + 1;
    }

    private static <T> boolean isAllElementsNull(List<T> list) {
        for (Object object : list) {
            if (object != null)
                return false;
        }

        return true;
    }

}

Salida 1:

         2               
        / \       
       /   \      
      /     \     
     /       \    
     7       5       
    / \     / \   
   /   \   /   \  
   2   6   3   6   
  / \ / \ / \ / \ 
  5 8 4 5 8 4 5 8 

Salida 2:

       2               
      / \       
     /   \      
    /     \     
   /       \    
   7       5       
  / \       \   
 /   \       \  
 2   6       9   
    / \     /   
    5 8     4   
michal.kreuzman
fuente
1
¿Cómo convertir esta salida a horizontal?
jijesh Aj
Para salida horizontal es mejor usar la solución de Vasya Novikov.
michal.kreuzman
3
Será genial si puedes elaborar 2 ^ n - 1 como primeros espacios y 2 ^ (n + 1) - 1 como espacios intermedios
DJ '
Es bueno para árboles equilibrados, ya que lo probé para uno de los árboles con 15 valores sesgados a la derecha y se volvió muy inmanejable ver la impresión.
akhil_mittal
3
Mi árbol tiene 44 capas de profundidad, por lo que Java se bloquea al intentar imprimir 8796093022207 espacios en blanco. Así que ten cuidado.
CX gamer
286

Imprima un árbol [grande] por líneas.

ejemplo de salida:

z
├── c
   ├── a
   └── b
├── d
├── e
   └── asdf
└── f

código:

public class TreeNode {

    final String name;
    final List<TreeNode> children;

    public TreeNode(String name, List<TreeNode> children) {
        this.name = name;
        this.children = children;
    }

    public String toString() {
        StringBuilder buffer = new StringBuilder(50);
        print(buffer, "", "");
        return buffer.toString();
    }

    private void print(StringBuilder buffer, String prefix, String childrenPrefix) {
        buffer.append(prefix);
        buffer.append(name);
        buffer.append('\n');
        for (Iterator<TreeNode> it = children.iterator(); it.hasNext();) {
            TreeNode next = it.next();
            if (it.hasNext()) {
                next.print(buffer, childrenPrefix + "├── ", childrenPrefix + "│   ");
            } else {
                next.print(buffer, childrenPrefix + "└── ", childrenPrefix + "    ");
            }
        }
    }
}

PD Esta respuesta no se enfoca exactamente en árboles "binarios", sino que imprime todo tipo de árboles. La solución está inspirada en el comando "árbol" en Linux.

VasiliNovikov
fuente
¿Esta solución maneja árboles binarios sesgados correctos?
patentfox
@VasyaNovikov, ¿cómo volvería a escribir children.get(children.size() - 1)si HashMap se usara para niños? Me las arreglé para modificar todas las otras partes excepto esta.
Le Nguyen Duy Anh
@LeNguyenDuyAnh, ¿cuál es la firma de tipo propuesta de HashMap? HashMap<String, List<String>>?
VasiliNovikov
He implementado mi árbol como HashMap<String, Node>. La cadena es la identificación del nodo.
Le Nguyen Duy Anh
De hecho, implementé algo similar en una pequeña biblioteca Java llamada text-tree . Quizás ayude a alguien.
Barfuin
47

He creado un algoritmo mejorado para esto, que maneja muy bien los nodos con diferentes tamaños. Imprime de arriba hacia abajo usando líneas.

package alg;

import java.util.ArrayList;
import java.util.List;


/**
 * Binary tree printer
 * 
 * @author MightyPork
 */
public class TreePrinter
{
    /** Node that can be printed */
    public interface PrintableNode
    {
        /** Get left child */
        PrintableNode getLeft();


        /** Get right child */
        PrintableNode getRight();


        /** Get text to be printed */
        String getText();
    }


    /**
     * Print a tree
     * 
     * @param root
     *            tree root node
     */
    public static void print(PrintableNode root)
    {
        List<List<String>> lines = new ArrayList<List<String>>();

        List<PrintableNode> level = new ArrayList<PrintableNode>();
        List<PrintableNode> next = new ArrayList<PrintableNode>();

        level.add(root);
        int nn = 1;

        int widest = 0;

        while (nn != 0) {
            List<String> line = new ArrayList<String>();

            nn = 0;

            for (PrintableNode n : level) {
                if (n == null) {
                    line.add(null);

                    next.add(null);
                    next.add(null);
                } else {
                    String aa = n.getText();
                    line.add(aa);
                    if (aa.length() > widest) widest = aa.length();

                    next.add(n.getLeft());
                    next.add(n.getRight());

                    if (n.getLeft() != null) nn++;
                    if (n.getRight() != null) nn++;
                }
            }

            if (widest % 2 == 1) widest++;

            lines.add(line);

            List<PrintableNode> tmp = level;
            level = next;
            next = tmp;
            next.clear();
        }

        int perpiece = lines.get(lines.size() - 1).size() * (widest + 4);
        for (int i = 0; i < lines.size(); i++) {
            List<String> line = lines.get(i);
            int hpw = (int) Math.floor(perpiece / 2f) - 1;

            if (i > 0) {
                for (int j = 0; j < line.size(); j++) {

                    // split node
                    char c = ' ';
                    if (j % 2 == 1) {
                        if (line.get(j - 1) != null) {
                            c = (line.get(j) != null) ? '┴' : '┘';
                        } else {
                            if (j < line.size() && line.get(j) != null) c = '└';
                        }
                    }
                    System.out.print(c);

                    // lines and spaces
                    if (line.get(j) == null) {
                        for (int k = 0; k < perpiece - 1; k++) {
                            System.out.print(" ");
                        }
                    } else {

                        for (int k = 0; k < hpw; k++) {
                            System.out.print(j % 2 == 0 ? " " : "─");
                        }
                        System.out.print(j % 2 == 0 ? "┌" : "┐");
                        for (int k = 0; k < hpw; k++) {
                            System.out.print(j % 2 == 0 ? "─" : " ");
                        }
                    }
                }
                System.out.println();
            }

            // print line of numbers
            for (int j = 0; j < line.size(); j++) {

                String f = line.get(j);
                if (f == null) f = "";
                int gap1 = (int) Math.ceil(perpiece / 2f - f.length() / 2f);
                int gap2 = (int) Math.floor(perpiece / 2f - f.length() / 2f);

                // a number
                for (int k = 0; k < gap1; k++) {
                    System.out.print(" ");
                }
                System.out.print(f);
                for (int k = 0; k < gap2; k++) {
                    System.out.print(" ");
                }
            }
            System.out.println();

            perpiece /= 2;
        }
    }
}

Para usar esto para su árbol, deje que su Nodeclase implemente PrintableNode.

Salida de ejemplo:

                                         2952:0                                             
                    ┌───────────────────────┴───────────────────────┐                       
                 1249:-1                                         5866:0                     
        ┌───────────┴───────────┐                       ┌───────────┴───────────┐           
     491:-1                  1572:0                  4786:1                  6190:0         
  ┌─────┘                                               └─────┐           ┌─────┴─────┐     
339:0                                                      5717:0      6061:0      6271:0   
MightyPork
fuente
Estaba tratando de replicar la técnica de "respuesta seleccionada". Pero creo que esta es una de las mejores respuestas aquí. Tan robusto y conciso.
Vikrant Goel
Después de implementar esto, parece funcionar muy bien, pero solo para árboles equilibrados. Cualquier desequilibrio devuelve resultados extraños.
mitbanip
Obtengo en ???????????lugar de las líneas entre nodos, pero debería ser solo un problema UTF8 ans stuff. De todos modos, grandes cosas, tengo que decir. La mejor respuesta para mí, ya que es realmente fácil de usar.
Fitz
Sí, eso fue todo. Solo tenía que cambiar todos los caracteres especiales de su párrafo de líneas y espacios .
Fitz
Agradable, para admitir la impresión de una variedad de elementos, creó una esencia que simplemente hace eso usando la lógica @MightyPork para imprimir el árbol. Verpublic static <T> void print(T[] elems)
Neo
40
public static class Node<T extends Comparable<T>> {
    T value;
    Node<T> left, right;

    public void insertToTree(T v) {
        if (value == null) {
            value = v;
            return;
        }
        if (v.compareTo(value) < 0) {
            if (left == null) {
                left = new Node<T>();
            }
            left.insertToTree(v);
        } else {
            if (right == null) {
                right = new Node<T>();
            }
            right.insertToTree(v);
        }
    }

    public void printTree(OutputStreamWriter out) throws IOException {
        if (right != null) {
            right.printTree(out, true, "");
        }
        printNodeValue(out);
        if (left != null) {
            left.printTree(out, false, "");
        }
    }
    private void printNodeValue(OutputStreamWriter out) throws IOException {
        if (value == null) {
            out.write("<null>");
        } else {
            out.write(value.toString());
        }
        out.write('\n');
    }
    // use string and not stringbuffer on purpose as we need to change the indent at each recursion
    private void printTree(OutputStreamWriter out, boolean isRight, String indent) throws IOException {
        if (right != null) {
            right.printTree(out, true, indent + (isRight ? "        " : " |      "));
        }
        out.write(indent);
        if (isRight) {
            out.write(" /");
        } else {
            out.write(" \\");
        }
        out.write("----- ");
        printNodeValue(out);
        if (left != null) {
            left.printTree(out, false, indent + (isRight ? " |      " : "        "));
        }
    }

}

imprimirá:

                 /----- 20
                 |       \----- 15
         /----- 14
         |       \----- 13
 /----- 12
 |       |       /----- 11
 |       \----- 10
 |               \----- 9
8
 |               /----- 7
 |       /----- 6
 |       |       \----- 5
 \----- 4
         |       /----- 3
         \----- 2
                 \----- 1

para la entrada

8 4 12 2 6 10 14 1 3 5 7 9 11 13 20 15

esta es una variante de la respuesta de @ anurag: me molestaba ver los | s adicionales

Laurent Demailly
fuente
Sería increíble si pudieras rotarlo 90 °.
Abhijit Sarkar
34

Adaptado de la respuesta de Vasya Novikov para hacerlo más binario , y usar a para eficiencia (concatenar objetos juntos en Java es generalmente ineficiente).StringBuilderString

public StringBuilder toString(StringBuilder prefix, boolean isTail, StringBuilder sb) {
    if(right!=null) {
        right.toString(new StringBuilder().append(prefix).append(isTail ? "│   " : "    "), false, sb);
    }
    sb.append(prefix).append(isTail ? "└── " : "┌── ").append(value.toString()).append("\n");
    if(left!=null) {
        left.toString(new StringBuilder().append(prefix).append(isTail ? "    " : "│   "), true, sb);
    }
    return sb;
}

@Override
public String toString() {
    return this.toString(new StringBuilder(), true, new StringBuilder()).toString();
}

Salida:

       ┌── 7
   ┌── 6
      └── 5
└── 4
       ┌── 3
    └── 2
        └── 1
            └── 0
Todd Davies
fuente
No funciona para un árbol cuando insertamos valores: 30,40,50,60,70,80 en un BST. Como eso crea un árbol sesgado a la derecha. El valor de isTail debe ser falso cuando right != null. Hice la edición y la probé, funciona bien.
akhil_mittal
Gracias por el aporte, acabo de editar la respuesta, ¿eso es mejor?
Todd Davies
Gracias, la respuesta de @Vasya Novikov es excelente, pero necesito una versión de la lista de enlaces, y su respuesta se ajusta a mi caso.
hychou
En todas las respuestas, esto produce el mejor árbol, ¡y el código es muy limpio!
p-sun
15

michal.kreuzman agradable que tendré que decir.

Me sentía flojo para hacer un programa solo y buscando código en la red cuando encontré esto, realmente me ayudó.

Pero me temo ver que funciona solo para un solo dígito, como si fuera a usar más de un dígito, ya que está usando espacios y no pestañas, la estructura se extraviará y el programa perderá su uso.

En cuanto a mis códigos posteriores, necesitaba algunas entradas más grandes (al menos más de 10), esto no funcionó para mí, y después de buscar mucho en la red cuando no encontré nada, hice un programa yo mismo.

Tiene algunos errores ahora, de nuevo en este momento me siento flojo para corregirlos, pero imprime muy bien y los nodos pueden tener un gran valor.

El árbol no va a ser como la pregunta menciona pero tiene 270 grados de rotación :)

public static void printBinaryTree(TreeNode root, int level){
    if(root==null)
         return;
    printBinaryTree(root.right, level+1);
    if(level!=0){
        for(int i=0;i<level-1;i++)
            System.out.print("|\t");
            System.out.println("|-------"+root.val);
    }
    else
        System.out.println(root.val);
    printBinaryTree(root.left, level+1);
}    

Coloque esta función con su propio TreeNode especificado y mantenga el nivel inicialmente 0, ¡y disfrute!

Estas son algunas de las salidas de muestra:

|       |       |-------11
|       |-------10
|       |       |-------9
|-------8
|       |       |-------7
|       |-------6
|       |       |-------5
4
|       |-------3
|-------2
|       |-------1


|       |       |       |-------10
|       |       |-------9
|       |-------8
|       |       |-------7
|-------6
|       |-------5
4
|       |-------3
|-------2
|       |-------1

El único problema es con las ramas extendidas; Intentaré resolver el problema lo antes posible, pero hasta entonces puedes usarlo también.

Anurag Agarwal
fuente
14

Su árbol necesitará el doble de distancia para cada capa:

       una
      / \
     / \
    / \
   / \
   antes de Cristo
  / \ / \
 / \ / \
 defg
/ \ / \ / \ / \
hijklmno

Puede guardar su árbol en una matriz de matrices, una matriz para cada profundidad:

[[a], [b, c], [d, e, f, g], [h, i, j, k, l, m, n, o]]

Si su árbol no está lleno, debe incluir valores vacíos en esa matriz:

       una
      / \
     / \
    / \
   / \
   antes de Cristo
  / \ / \
 / \ / \
 defg
/ \ \ / \ \
hiklmo
[[a], [b, c], [d, e, f, g], [h, i,, k, l, m,, o]]

Luego, puede iterar sobre la matriz para imprimir su árbol, imprimir espacios antes del primer elemento y entre los elementos según la profundidad e imprimir las líneas según si los elementos correspondientes en la matriz para la siguiente capa están llenos o no. Si sus valores pueden tener más de un carácter, necesita encontrar el valor más largo al crear la representación de matriz y multiplicar todos los anchos y el número de líneas en consecuencia.

hd42
fuente
¿Qué pasa si el árbol no está completo? En ese caso, parece que debería poder hacer esto sin duplicar el espacio en cada nivel.
templatetypedef
Sí, pero sólo en algunos casos muy limitados en la mayoría de los subárboles están vinculados listas en lugar de árboles desde el mismo nivel hacia abajo o fueras a robar diferentes sub-estructuras con diferentes separaciones entre las capas ...
hd42
13

La respuesta de VasyaNovikov me pareció muy útil para imprimir un gran árbol general, y la modifiqué para un árbol binario

Código:

class TreeNode {
    Integer data = null;
    TreeNode left = null;
    TreeNode right = null;

    TreeNode(Integer data) {this.data = data;}

    public void print() {
        print("", this, false);
    }

    public void print(String prefix, TreeNode n, boolean isLeft) {
        if (n != null) {
            System.out.println (prefix + (isLeft ? "|-- " : "\\-- ") + n.data);
            print(prefix + (isLeft ? "|   " : "    "), n.left, true);
            print(prefix + (isLeft ? "|   " : "    "), n.right, false);
        }
    }
}

Salida de muestra:

\-- 7
    |-- 3
    |   |-- 1
    |   |   \-- 2
    |   \-- 5
    |       |-- 4
    |       \-- 6
    \-- 11
        |-- 9
        |   |-- 8
        |   \-- 10
        \-- 13
            |-- 12
            \-- 14
Nitin K
fuente
8

Una solución en lenguaje Scala , análoga a lo que escribí en Java :

case class Node(name: String, children: Node*) {

    def toTree: String = toTree("", "").mkString("\n")

    private def toTree(prefix: String, childrenPrefix: String): Seq[String] = {
        val firstLine = prefix + this.name

        val firstChildren = this.children.dropRight(1).flatMap { child =>
            child.toTree(childrenPrefix + "├── ", childrenPrefix + "│   ")
        }
        val lastChild = this.children.takeRight(1).flatMap { child =>
            child.toTree(childrenPrefix + "└── ", childrenPrefix + "    ")
        }
        firstLine +: firstChildren ++: lastChild
    }

}

Ejemplo de salida:

vasya
├── frosya
   ├── petya
      └── masha
   └── kolya
└── frosya2
VasiliNovikov
fuente
1
Con Lambda disponible en Java también, ¿tal vez desea actualizar su solución Java?
Tintín
@Tintin Scala no se trata solo de las funciones lambda. Pero si tiene en mente una buena mejora para Java, siéntase libre de "editar", que luego será aceptado por la comunidad StackOverflow si se considera beneficioso .;)
VasiliNovikov
5

Sé que todos ustedes tienen una gran solución; Solo quiero compartir el mío, tal vez esa no sea la mejor manera, ¡pero es perfecta para mí!

De pythonvez pipen cuando, ¡es realmente bastante simple! ¡AUGE!

En Mac o Ubuntu (el mío es mac)

  1. terminal abierta
  2. $ pip install drawtree
  3. $python, ingrese a la consola de Python; puedes hacerlo de otra manera
  4. from drawtree import draw_level_order
  5. draw_level_order('{2,1,3,0,7,9,1,2,#,1,0,#,#,8,8,#,#,#,#,7}')

¡HECHO!

        2
       / \
      /   \
     /     \
    1       3
   / \     / \
  0   7   9   1
 /   / \     / \
2   1   0   8   8
       /
      7

Seguimiento de la fuente:

Antes de ver esta publicación, busqué en google "texto plano de árbol binario"

Y encontré esto https://www.reddit.com/r/learnpython/comments/3naiq8/draw_binary_tree_in_plain_text/ , dirígeme a este https://github.com/msbanik/drawtree

Sean L
fuente
@DenysVitali oh sí, tienes razón): Probablemente debería mover esto a 'cómo imprimir el árbol desde el recorrido de orden de nivel serializado (cualquier lenguaje / python)'.
Sean L
3
No quería parecer grosero, pero cuando un usuario etiqueta la pregunta como javaespera una respuesta de Java :)
Denys Vitali
3
public void printPreety() {
    List<TreeNode> list = new ArrayList<TreeNode>();
    list.add(head);
    printTree(list, getHeight(head));
}

public int getHeight(TreeNode head) {

    if (head == null) {
        return 0;
    } else {
        return 1 + Math.max(getHeight(head.left), getHeight(head.right));
    }
}

/**
 * pass head node in list and height of the tree 
 * 
 * @param levelNodes
 * @param level
 */
private void printTree(List<TreeNode> levelNodes, int level) {

    List<TreeNode> nodes = new ArrayList<TreeNode>();

    //indentation for first node in given level
    printIndentForLevel(level);

    for (TreeNode treeNode : levelNodes) {

        //print node data
        System.out.print(treeNode == null?" ":treeNode.data);

        //spacing between nodes
        printSpacingBetweenNodes(level);

        //if its not a leaf node
        if(level>1){
            nodes.add(treeNode == null? null:treeNode.left);
            nodes.add(treeNode == null? null:treeNode.right);
        }
    }
    System.out.println();

    if(level>1){        
        printTree(nodes, level-1);
    }
}

private void printIndentForLevel(int level){
    for (int i = (int) (Math.pow(2,level-1)); i >0; i--) {
        System.out.print(" ");
    }
}

private void printSpacingBetweenNodes(int level){
    //spacing between nodes
    for (int i = (int) ((Math.pow(2,level-1))*2)-1; i >0; i--) {
        System.out.print(" ");
    }
}


Prints Tree in following format:
                4                               
        3               7               
    1               5       8       
      2                       10   
                             9   
Sujit Kamthe
fuente
2

Esta es una solución muy simple para imprimir un árbol. No es tan bonito, pero es realmente simple:

enum { kWidth = 6 };
void PrintSpace(int n)
{
  for (int i = 0; i < n; ++i)
    printf(" ");
}

void PrintTree(struct Node * root, int level)
{
  if (!root) return;
  PrintTree(root->right, level + 1);
  PrintSpace(level * kWidth);
  printf("%d", root->data);
  PrintTree(root->left, level + 1);
}

Salida de muestra:

      106
            105
104
            103
                  102
                        101
      100
Wenguang Wang
fuente
2

Basado en la respuesta de VasyaNovikov. Mejorado con algo de magia Java: interfaz genérica y funcional.

/**
 * Print a tree structure in a pretty ASCII fromat.
 * @param prefix Currnet previx. Use "" in initial call!
 * @param node The current node. Pass the root node of your tree in initial call.
 * @param getChildrenFunc A {@link Function} that returns the children of a given node.
 * @param isTail Is node the last of its sibblings. Use true in initial call. (This is needed for pretty printing.)
 * @param <T> The type of your nodes. Anything that has a toString can be used.
 */
private <T> void printTreeRec(String prefix, T node, Function<T, List<T>> getChildrenFunc, boolean isTail) {
    String nodeName = node.toString();
    String nodeConnection = isTail ? "└── " : "├── ";
    log.debug(prefix + nodeConnection + nodeName);
    List<T> children = getChildrenFunc.apply(node);
    for (int i = 0; i < children.size(); i++) {
        String newPrefix = prefix + (isTail ? "    " : "│   ");
        printTreeRec(newPrefix, children.get(i), getChildrenFunc, i == children.size()-1);
    }
}

Ejemplo de llamada inicial:

Function<ChecksumModel, List<ChecksumModel>> getChildrenFunc = node -> getChildrenOf(node)
printTreeRec("", rootNode, getChildrenFunc, true);

Producirá algo como

└── rootNode
    ├── childNode1
    ├── childNode2
       ├── childNode2.1
       ├── childNode2.2
       └── childNode2.3
    ├── childNode3
    └── childNode4
Robert
fuente
2

Escribí una impresora de árbol binario en Java.

El código está en GitHub aquí .

No se ha optimizado para la eficiencia del tiempo de ejecución, pero como estamos hablando de imprimir en ASCII, pensé que no se usaría en árboles muy grandes. Sin embargo, tiene algunas características agradables.

  1. Hace un uso eficiente del espacio ya que un subárbol grande se extiende debajo de uno más pequeño tanto como sea posible.
  2. Hay un parámetro para establecer el espacio horizontal mínimo entre las etiquetas de nodo.
  3. Las etiquetas de nodo son cadenas de longitud arbitraria.
  4. Además de un método para imprimir un solo árbol, hay un método para imprimir una lista de árboles horizontalmente en la página (con un parámetro para el ancho de la página), utilizando tantas filas como sea necesario.
  5. Hay una opción para imprimir árboles con ramas diagonales (usando caracteres de barra diagonal y barra invertida) o con ramas horizontales (usando caracteres de dibujo de cuadro ascii). Este último es más compacto y hace que los niveles de los árboles sean más claros visualmente.
  6. Funciona.

Algunos programas de demostración / prueba están incluidos.

A continuación, se muestra un ejemplo de un árbol binario generado aleatoriamente, tal como lo imprime el programa. Esto ilustra el uso eficiente del espacio, con un gran subárbol derecho que se extiende debajo de un pequeño subárbol izquierdo:

             seven                                        
              / \                                         
             /   \                                        
            /     \                                       
           /       \                                      
          /         \                                     
         /           \                                    
       five        thirteen                               
       / \           / \                                  
      /   \         /   \                                 
     /     \       /     \                                
  three    six    /       \                               
   / \           /         \                              
  /   \         /           \                             
one   four     /             \                            
  \           /               \                           
  two        /                 \                          
           nine            twenty four                    
           / \                 / \                        
          /   \               /   \                       
         /     \             /     \                      
      eight   twelve        /       \                     
               /           /         \                    
             ten          /           \                   
               \         /             \                  
              eleven    /               \                 
                       /                 \                
                      /                   \               
                     /                     \              
                 eighteen              twenty seven       
                   / \                     / \            
                  /   \                   /   \           
                 /     \                 /     \          
                /       \               /       \         
               /         \             /         \        
              /           \           /           \       
             /             \    twenty five   twenty eight
            /               \         \             \     
           /                 \     twenty six      thirty 
       fourteen            nineteen                 /     
           \                   \              twenty nine 
         sixteen           twenty three                   
           / \                 /                          
          /   \           twenty two                      
         /     \             /                            
        /       \         twenty                          
       /         \           \                            
   fifteen    seventeen   twenty one                      

Un ejemplo de impresión de los cinco árboles binarios de nodo (con etiquetas en orden) en la página:

one           one         one          one        one       one         one     
  \             \           \            \          \         \           \     
  two           two         two          two        two      three       three  
    \             \           \            \          \       / \         / \   
   three         three        four         five       five  two four    two five
      \             \         / \          /          /           \         /   
      four          five     /   \      three       four          five    four  
        \           /     three  five      \        /                           
        five      four                     four  three                          



one          one        one        one       one       one         one        two        
  \            \          \          \         \         \           \        / \        
  four         four       five       five      five      five        five    /   \       
  / \          / \        /          /         /         /           /     one  three    
two five      /   \     two        two      three      four        four            \     
  \        three  five    \          \       / \       /           /               four  
 three      /            three       four  two four  two        three                \   
          two               \        /                 \         /                   five
                            four  three               three    two                       



   two          two          two        two      three         three         three    
   / \          / \          / \        / \       / \           / \           / \     
  /   \       one four     one five   one five  one four       /   \        two four  
one  three        / \          /          /       \   \       /     \       /     \   
        \        /   \      three       four      two five  one     five  one     five
        five  three  five      \        /                     \     /                 
        /                      four  three                    two four                
      four                                                                            



   three      four      four         four         four            four       five    
    / \       / \       / \          / \          / \             / \        /       
  two five  one five  one five     two five      /   \           /   \     one       
  /   /       \         \          / \        three  five     three  five    \       
one four      two      three      /   \        /               /             two     
                \       /       one  three   one             two               \     
               three  two                      \             /                three  
                                               two         one                   \   
                                                                                 four



  five      five      five      five       five         five      five        five
  /         /         /         /          /            /         /           /   
one       one       one       one        two          two      three       three  
  \         \         \         \        / \          / \       / \         / \   
  two      three      four      four    /   \       one four  one four    two four
    \       / \       /         /     one  three        /       \         /       
    four  two four  two      three            \      three      two     one       
    /                 \       /               four                                
 three               three  two                                                   



    five      five         five        five          five
    /         /            /           /             /   
  four      four         four        four          four  
  /         /            /           /             /     
one       one          two        three         three    
  \         \          / \         /             /       
  two      three      /   \      one           two       
    \       /       one  three     \           /         
   three  two                      two       one 

El siguiente es un ejemplo del mismo árbol impreso en 4 formas diferentes, con espaciado horizontal de 1 y de 3, y con ramas diagonales y horizontales.

                   27        
             ┌─────┴─────┐   
             13          29  
      ┌──────┴──────┐  ┌─┴─┐ 
      8             23 28  30
   ┌──┴──┐       ┌──┴──┐     
   4     11      21    26    
 ┌─┴─┐  ┌┴┐    ┌─┴─┐  ┌┘     
 2   5  9 12   18  22 24     
┌┴┐  └┐ └┐   ┌─┴─┐    └┐     
1 3   6  10  17  19    25    
      └┐    ┌┘   └┐          
       7    15    20         
          ┌─┴─┐              
          14  16             


                 27        
                / \        
               /   \       
              13    29     
             / \   / \     
            /   \ 28  30   
           /     \         
          /       \        
         /         \       
        /           \      
       8             23    
      / \           / \    
     /   \         /   \   
    4     11      /     \  
   / \   / \     21      26
  2   5 9   12  / \     /  
 / \   \ \     18  22  24  
1   3   6 10  / \       \  
         \   17  19      25
          7 /     \        
           15      20      
          / \              
         14  16            


                             27            
                    ┌────────┴────────┐    
                    13                29   
          ┌─────────┴─────────┐    ┌──┴──┐ 
          8                   23   28    30
     ┌────┴────┐         ┌────┴────┐       
     4         11        21        26      
  ┌──┴──┐    ┌─┴─┐    ┌──┴──┐     ┌┘       
  2     5    9   12   18    22    24       
┌─┴─┐   └┐   └┐    ┌──┴──┐        └┐       
1   3    6    10   17    19        25      
         └┐       ┌┘     └┐                
          7       15      20               
               ┌──┴──┐                     
               14    16                    


                      27         
                     / \         
                    /   \        
                   /     \       
                  /       \      
                 13        29    
                / \       / \    
               /   \     /   \   
              /     \   28    30 
             /       \           
            /         \          
           /           \         
          /             \        
         /               \       
        8                 23     
       / \               / \     
      /   \             /   \    
     /     \           /     \   
    4       11        /       \  
   / \     / \       21        26
  2   5   9   12    / \       /  
 / \   \   \       /   \     24  
1   3   6   10    18    22    \  
         \       / \           25
          7     /   \            
               17    19          
              /       \          
             15        20        
            / \                  
           /   \                 
          14    16               
Bill Vanyo
fuente
Es bueno que hayas escrito y publicado este proyecto. Parece que hace un buen trabajo, pero básicamente solo un enlace a su biblioteca no es una buena respuesta en Stack Overflow. Como mínimo, debe incluir el código necesario para usar su biblioteca para mostrar los ejemplos que ha proporcionado, para que las personas sepan qué implica el uso de su biblioteca. En este momento, esto es solo un anuncio para su repositorio de GitHub. Eso no es malo, si le estás mostrando a la gente cómo usarlo realmente.
Makyen
Por cierto: si edita en el código de ejemplo, por favor envíeme un ping aquí incluyéndolo @Makyenen un comentario.
Makyen
2

Esta es una pregunta interesante, y también escribí un proyecto para ello.

Impresora de árbol binario

Aquí hay unos ejemplos:

Imprime BST al azar.

BTPrinter.printRandomBST(100, 100);
                              38                                  
                              / \                                 
                             /   \                                
                            /     \                               
                           /       \                              
                          /         \                             
                         /           \                            
                        /             \                           
                       /               \                          
                      /                 \                         
                     /                   \                        
                    /                     \                       
                   /                       \                      
                  /                         \                     
                 /                           \                    
                /                             \                   
               /                               \                  
              28                               82                 
             / \                               / \                
            /   \                             /   \               
           /     \                           /     \              
          /       \                         /       \             
         5        31                       /         \            
        / \       / \                     /           \           
       /   \     30 36                   /             \          
      /     \   /   / \                 /               \         
     /       \ 29  33 37               /                 \        
    /         \   / \                 /                   \       
   /           \ 32 35               65                   95      
  1            14   /               / \                   / \     
 / \           / \ 34              /   \                 94 97    
0   2         /   \               /     \               /   / \   
     \       12   24             /       \             93  96 98  
      3     / \   / \           /         \           /         \ 
       \   9  13 16 25         /           \         84         99
        4 / \   / \   \       /             \       / \           
         7  10 15 23  26     59             74     83 86          
        / \   \   /     \   / \             / \       / \         
       6   8  11 22     27 56 60           73 76     85 91        
                /         / \   \         /   / \       / \       
               20        /   \  61       67  75 79     88 92      
              / \       40   58   \     / \     / \   / \         
             18 21     / \   /    62   66 72   78 80 87 89        
            / \       39 54 57      \     /   /     \     \       
           17 19         / \        64   69  77     81    90      
                        50 55       /   / \                       
                       / \         63  68 70                      
                      /   \                 \                     
                     /     \                71                    
                    47     53                                     
                   / \     /                                      
                  /   \   52                                      
                 42   49 /                                        
                / \   / 51                                        
               41 43 48                                           
                    \                                             
                    46                                            
                    /                                             
                   45                                             
                  /                                               
                 44     

Imprimir árbol desde la matriz de orden de nivel de estilo leetcode, '#' significa un terminador de ruta donde no existe ningún nodo a continuación.

BTPrinter.printTree("1,2,3,4,5,#,#,6,7,8,1,#,#,#,#,#,#,2,3,4,5,6,7,8,9,10,11,12,13,14,15");
        1              
       / \             
      2   3            
     / \               
    /   \              
   4     5             
  / \   / \            
 6   7 8   1           
          / \          
         /   \         
        /     \        
       /       \       
      /         \      
     2           3     
    / \         / \    
   /   \       /   \   
  4     5     6     7  
 / \   / \   / \   / \ 
8   9 10 11 12 13 14 15
afkbrb
fuente
1

Necesitaba imprimir un árbol binario en uno de mis proyectos, para eso he preparado una clase java TreePrinter, uno de los resultados de la muestra es:

                [+]
               /   \
              /     \
             /       \
            /         \
           /           \
        [*]             \
       /   \             [-]
[speed]     [2]         /   \
                    [45]     [12]

Aquí está el código para la clase TreePrinterjunto con la clase TextNode. Para imprimir cualquier árbol, puede crear un árbol equivalente con TextNodeclase.


import java.util.ArrayList;

public class TreePrinter {

    public TreePrinter(){
    }

    public static String TreeString(TextNode root){
        ArrayList layers = new ArrayList();
        ArrayList bottom = new ArrayList();

        FillBottom(bottom, root);  DrawEdges(root);

        int height = GetHeight(root);
        for(int i = 0; i  s.length()) min = s.length();

            if(!n.isEdge) s += "[";
            s += n.text;
            if(!n.isEdge) s += "]";

            layers.set(n.depth, s);
        }

        StringBuilder sb = new StringBuilder();

        for(int i = 0; i  temp = new ArrayList();

            for(int i = 0; i  0) temp.get(i-1).left = x;
                temp.add(x);
            }

            temp.get(count-1).left = n.left;
            n.left.depth = temp.get(count-1).depth+1;
            n.left = temp.get(0);

            DrawEdges(temp.get(count-1).left);
        }
        if(n.right != null){
            int count = n.right.x - (n.x + n.text.length() + 2);
            ArrayList temp = new ArrayList();

            for(int i = 0; i  0) temp.get(i-1).right = x;
                temp.add(x);
            }

            temp.get(count-1).right = n.right;
            n.right.depth = temp.get(count-1).depth+1;
            n.right = temp.get(0);  

            DrawEdges(temp.get(count-1).right);
        }
    }

    private static void FillBottom(ArrayList bottom, TextNode n){
        if(n == null) return;

        FillBottom(bottom, n.left);

        if(!bottom.isEmpty()){            
            int i = bottom.size()-1;
            while(bottom.get(i).isEdge) i--;
            TextNode last = bottom.get(i);

            if(!n.isEdge) n.x = last.x + last.text.length() + 3;
        }
        bottom.add(n);
        FillBottom(bottom, n.right);
    }

    private static boolean isLeaf(TextNode n){
        return (n.left == null && n.right == null);
    }

    private static int GetHeight(TextNode n){
        if(n == null) return 0;

        int l = GetHeight(n.left);
        int r = GetHeight(n.right);

        return Math.max(l, r) + 1;
    }
}


class TextNode {
    public String text;
    public TextNode parent, left, right;
    public boolean isEdge;
    public int x, depth;

    public TextNode(String text){
        this.text = text;
        parent = null; left = null; right = null;
        isEdge = false;
        x = 0; depth = 0;
    }
}

Finalmente, aquí hay una clase de prueba para imprimir una muestra dada:


public class Test {

    public static void main(String[] args){
        TextNode root = new TextNode("+");
        root.left = new TextNode("*");            root.left.parent = root;
        root.right = new TextNode("-");           root.right.parent = root;
        root.left.left = new TextNode("speed");   root.left.left.parent = root.left;
        root.left.right = new TextNode("2");      root.left.right.parent = root.left;
        root.right.left = new TextNode("45");     root.right.left.parent = root.right;
        root.right.right = new TextNode("12");    root.right.right.parent = root.right;

        System.out.println(TreePrinter.TreeString(root));
    }
}
anuragsn7
fuente
1

Puede usar un applet para visualizar esto muy fácilmente. Necesita imprimir los siguientes elementos.

  1. Imprima los nodos como círculos con un radio visible

    • Obtenga las coordenadas para cada nodo.

    • La coordenada x se puede visualizar como el número de nodos visitados antes de que el nodo sea visitado en su recorrido transversal.

    • La coordenada y se puede visualizar como la profundidad del nodo particular.


  1. Imprime las líneas entre padres e hijos

    • Esto se puede hacer manteniendo las coordenadas x e y de los nodos y los padres de cada nodo en listas separadas.

    • Para cada nodo, excepto la raíz, unir cada nodo con su padre tomando las coordenadas xey del niño y el padre.

kaushalpranav
fuente
¿Puedes visualizar y dar una mejor solución que las respuestas existentes?
Enamul Hassan
1
private StringBuilder prettyPrint(Node root, int currentHeight, int totalHeight) {
        StringBuilder sb = new StringBuilder();
        int spaces = getSpaceCount(totalHeight-currentHeight + 1);
        if(root == null) {
            //create a 'spatial' block and return it
            String row = String.format("%"+(2*spaces+1)+"s%n", "");
            //now repeat this row space+1 times
            String block = new String(new char[spaces+1]).replace("\0", row);
            return new StringBuilder(block);
        }
        if(currentHeight==totalHeight) return new StringBuilder(root.data+"");
        int slashes = getSlashCount(totalHeight-currentHeight +1);
        sb.append(String.format("%"+(spaces+1)+"s%"+spaces+"s", root.data+"", ""));
        sb.append("\n");
        //now print / and \
        // but make sure that left and right exists
        char leftSlash = root.left == null? ' ':'/';
        char rightSlash = root.right==null? ' ':'\\';
        int spaceInBetween = 1;
        for(int i=0, space = spaces-1; i<slashes; i++, space --, spaceInBetween+=2) {
            for(int j=0; j<space; j++) sb.append(" ");
            sb.append(leftSlash);
            for(int j=0; j<spaceInBetween; j++) sb.append(" ");
            sb.append(rightSlash+"");
            for(int j=0; j<space; j++) sb.append(" ");
            sb.append("\n");
        }
        //sb.append("\n");

        //now get string representations of left and right subtrees
        StringBuilder leftTree = prettyPrint(root.left, currentHeight+1, totalHeight);
        StringBuilder rightTree = prettyPrint(root.right, currentHeight+1, totalHeight);
        // now line by line print the trees side by side
        Scanner leftScanner = new Scanner(leftTree.toString());
        Scanner rightScanner = new Scanner(rightTree.toString());
//      spaceInBetween+=1;
        while(leftScanner.hasNextLine()) {
            if(currentHeight==totalHeight-1) {
                sb.append(String.format("%-2s %2s", leftScanner.nextLine(), rightScanner.nextLine()));
                sb.append("\n");
                spaceInBetween-=2;              
            }
            else {
                sb.append(leftScanner.nextLine());
                sb.append(" ");
                sb.append(rightScanner.nextLine()+"\n");
            }
        }

        return sb;

    }
private int getSpaceCount(int height) {
        return (int) (3*Math.pow(2, height-2)-1);
    }
private int getSlashCount(int height) {
        if(height <= 3) return height -1;
        return (int) (3*Math.pow(2, height-3)-1);
    }

https://github.com/murtraja/java-binary-tree-printer

solo funciona para enteros de 1 a 2 dígitos (fui flojo para hacerlo genérico)

sesgada completo

Murtaza Raja
fuente
1

Esta fue la solución más simple para la vista horizontal. Intenté con muchos ejemplos. Funciona bien para mi propósito. Actualizado de la respuesta de @ nitin-k.

public void print(String prefix, BTNode n, boolean isLeft) {
    if (n != null) {
        print(prefix + "     ", n.right, false);
        System.out.println (prefix + ("|-- ") + n.data);
        print(prefix + "     ", n.left, true);
    }
}

Llamada:

bst.print("", bst.root, false);

Solución:

                         |-- 80
                    |-- 70
               |-- 60
          |-- 50
     |-- 40
|-- 30
     |-- 20
          |-- 10
navderm
fuente
1
  1. Necesitarás nivelar el orden para atravesar tu árbol.
  2. Elija la longitud del nodo y la longitud del espacio .
  3. Obtenga el ancho base del árbol en relación con cada nivel que sea node_length * nodes_count + space_length * spaces_count*.
  4. Encuentre una relación entre ramificación, espaciado, sangría y el ancho base calculado.

Código en GitHub: YoussefRaafatNasry / bst-ascii-visualización

                                             07                     
                                             /\                     
                                            /  \                    
                                           /    \                   
                                          /      \                  
                                         /        \                 
                                        /          \                
                                       /            \               
                                      /              \              
                                     /                \             
                                    /                  \            
                                   /                    \           
                                 03                      11         
                                 /\                      /\         
                                /  \                    /  \        
                               /    \                  /    \       
                              /      \                /      \      
                             /        \              /        \     
                           01          05          09          13   
                           /\          /\          /\          /\   
                          /  \        /  \        /  \        /  \  
                        00    02    04    06    08    10    12    14
YoussefRaafatNasry
fuente
Yo diría que el código es lo suficientemente corto como para que pueda incrustarlo en su respuesta.
m02ph3u5
El código no es solo la visualizefunción, es la visualizerclase completa que tiene aproximadamente 200 loc, incluido el archivo de encabezado.
YoussefRaafatNasry
1

Para aquellos que buscan la solución Rust:

pub struct Node {
  pub value: i32,
  left: Option<Box<Node>>,
  right: Option<Box<Node>>
}

impl Node {

  pub fn new(val: i32) -> Node {
    Node {
      value: val,
      left: None,
      right: None
    }
  }

  pub fn getLeftNode(&self) -> Option<&Node> {
   self.left.as_deref()
  }

  pub fn getRightNode(&self) -> Option<&Node> {
   self.right.as_deref()
  }

  pub fn setLeftNode(&mut self, val: i32) -> &mut Node {
   self.left = Some(Box::new(Node::new(val)));
   self.left.as_deref_mut().unwrap()
  }

  pub fn setRightNode(&mut self, val: i32) -> &mut Node {
   self.right = Some(Box::new(Node::new(val)));
   self.right.as_deref_mut().unwrap()
  }

  fn visualizeTree(&self, level: u16, is_tail: bool, columns: &mut HashSet<u16>) {
    let left = self.getLeftNode();
    let right = self.getRightNode();

    if right.is_some() {
      right.unwrap().visualizeTree(level+1, false, columns);
    }

    if level > 0 {
      for i in 0..level-1 {
          if columns.contains(&i) {
            print!("│   ");
          } else {
            print!("    ");
          }
      }
      if is_tail {
        println!("└── {}", self.value);
        columns.remove(&(level-1));
        columns.insert(level);
      } else {
        println!("┌── {}", self.value);
        columns.insert(level);
        columns.insert(level-1);
      }
    } else {
      println!("{}", self.value);
    }

    if left.is_some() {
      left.unwrap().visualizeTree(level+1, true, columns);
    }
  }

  pub fn printTree(&self) {
    let mut columns = HashSet::new();
    columns.insert(0);
    self.visualizeTree(0, true, &mut columns);
  }
}

El resultado es algo como esto:

┌── 17
      ┌── 3
         └── 9
   └── 2
       └── 1
20
   ┌── 7
         ┌── 16
      └── 15
└── 8
       ┌── 11
    └── 4
        └── 13
Arsenio
fuente
0

Imprimir en la consola:

                                                500
                       700                                             300   
    200                                   400                                                                                          

Código simple:

public int getHeight()
    {
        if(rootNode == null) return -1;
        return getHeight(rootNode);
    }

    private int getHeight(Node node)
    {
        if(node == null) return -1;

        return Math.max(getHeight(node.left), getHeight(node.right)) + 1;
    }

    public void printBinaryTree(Node rootNode)
    {
        Queue<Node> rootsQueue = new LinkedList<Node>();
        Queue<Node> levelQueue = new LinkedList<Node>();
        levelQueue.add(rootNode);
        int treeHeight = getHeight();
        int firstNodeGap;
        int internalNodeGap;
        int copyinternalNodeGap;
        while(true)
        {
            System.out.println("");
            internalNodeGap = (int)(Math.pow(2, treeHeight + 1) -1);  
            copyinternalNodeGap = internalNodeGap;
            firstNodeGap = internalNodeGap/2;

            boolean levelFirstNode = true;

            while(!levelQueue.isEmpty())
            {
                internalNodeGap = copyinternalNodeGap;
                Node currNode = levelQueue.poll();
                if(currNode != null)
                {
                    if(levelFirstNode)
                    {
                        while(firstNodeGap > 0)
                        {
                            System.out.format("%s", "   ");
                            firstNodeGap--; 
                        }
                        levelFirstNode =false;
                    }
                    else
                    {
                        while(internalNodeGap>0)
                        {
                            internalNodeGap--;
                            System.out.format("%s", "   ");
                        }
                    }
                    System.out.format("%3d",currNode.data);
                    rootsQueue.add(currNode);
                }
            }

            --treeHeight;

            while(!rootsQueue.isEmpty())
            {
                Node currNode = rootsQueue.poll();
                if(currNode != null)
                {
                    levelQueue.add(currNode.left);
                    levelQueue.add(currNode.right);
                }
            }

            if(levelQueue.isEmpty()) break;
        }

    }
Divang
fuente
0

Aquí hay una impresora de árbol muy versátil. No es el mejor, pero maneja muchos casos. Siéntase libre de agregar barras inclinadas si puede resolverlo. ingrese la descripción de la imagen aquí

package com.tomac120.NodePrinter;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by elijah on 6/28/16.
 */
public class NodePrinter{
    final private List<List<PrintableNodePosition>> nodesByRow;
    int maxColumnsLeft = 0;
    int maxColumnsRight = 0;
    int maxTitleLength = 0;
    String sep = " ";
    int depth = 0;

    public NodePrinter(PrintableNode rootNode, int chars_per_node){
        this.setDepth(rootNode,1);
        nodesByRow = new ArrayList<>(depth);
        this.addNode(rootNode._getPrintableNodeInfo(),0,0);
        for (int i = 0;i<chars_per_node;i++){
            //sep += " ";
        }
    }

    private void setDepth(PrintableNode info, int depth){
        if (depth > this.depth){
            this.depth = depth;
        }
        if (info._getLeftChild() != null){
            this.setDepth(info._getLeftChild(),depth+1);
        }
        if (info._getRightChild() != null){
            this.setDepth(info._getRightChild(),depth+1);
        }
    }

    private void addNode(PrintableNodeInfo node, int level, int position){
        if (position < 0 && -position > maxColumnsLeft){
            maxColumnsLeft = -position;
        }
        if (position > 0 && position > maxColumnsRight){
            maxColumnsRight = position;
        }
        if (node.getTitleLength() > maxTitleLength){
           maxTitleLength = node.getTitleLength();
        }
        List<PrintableNodePosition> row = this.getRow(level);
        row.add(new PrintableNodePosition(node, level, position));
        level++;

        int depthToUse = Math.min(depth,6);
        int levelToUse = Math.min(level,6);
        int offset = depthToUse - levelToUse-1;
        offset = (int)(Math.pow(offset,Math.log(depthToUse)*1.4));
        offset = Math.max(offset,3);


        PrintableNodeInfo leftChild = node.getLeftChildInfo();
        PrintableNodeInfo rightChild = node.getRightChildInfo();
        if (leftChild != null){
            this.addNode(leftChild,level,position-offset);
        }
        if (rightChild != null){
            this.addNode(rightChild,level,position+offset);
        }
    }

    private List<PrintableNodePosition> getRow(int row){
        if (row > nodesByRow.size() - 1){
            nodesByRow.add(new LinkedList<>());
        }
        return nodesByRow.get(row);
    }

    public void print(){
        int max_chars = this.maxColumnsLeft+maxColumnsRight+1;
        int level = 0;
        String node_format = "%-"+this.maxTitleLength+"s";
        for (List<PrintableNodePosition> pos_arr : this.nodesByRow){
            String[] chars = this.getCharactersArray(pos_arr,max_chars);
            String line = "";
            int empty_chars = 0;
            for (int i=0;i<chars.length+1;i++){
                String value_i = i < chars.length ? chars[i]:null;
                if (chars.length + 1 == i || value_i != null){
                    if (empty_chars > 0) {
                        System.out.print(String.format("%-" + empty_chars + "s", " "));
                    }
                    if (value_i != null){
                        System.out.print(String.format(node_format,value_i));
                        empty_chars = -1;
                    } else{
                        empty_chars = 0;
                    }
                } else {
                    empty_chars++;
                }
            }
            System.out.print("\n");

            int depthToUse = Math.min(6,depth);
            int line_offset = depthToUse - level;
            line_offset *= 0.5;
            line_offset = Math.max(0,line_offset);

            for (int i=0;i<line_offset;i++){
                System.out.println("");
            }


            level++;
        }
    }

    private String[] getCharactersArray(List<PrintableNodePosition> nodes, int max_chars){
        String[] positions = new String[max_chars+1];
        for (PrintableNodePosition a : nodes){
            int pos_i = maxColumnsLeft + a.column;
            String title_i = a.nodeInfo.getTitleFormatted(this.maxTitleLength);
            positions[pos_i] = title_i;
        }
        return positions;
    }
}

Clase NodeInfo

package com.tomac120.NodePrinter;

/**
 * Created by elijah on 6/28/16.
 */
public class PrintableNodeInfo {
    public enum CLI_PRINT_COLOR {
        RESET("\u001B[0m"),
        BLACK("\u001B[30m"),
        RED("\u001B[31m"),
        GREEN("\u001B[32m"),
        YELLOW("\u001B[33m"),
        BLUE("\u001B[34m"),
        PURPLE("\u001B[35m"),
        CYAN("\u001B[36m"),
        WHITE("\u001B[37m");

        final String value;
        CLI_PRINT_COLOR(String value){
            this.value = value;
        }

        @Override
        public String toString() {
            return value;
        }
    }
    private final String title;
    private final PrintableNode leftChild;
    private final PrintableNode rightChild;
    private final CLI_PRINT_COLOR textColor;

    public PrintableNodeInfo(String title, PrintableNode leftChild, PrintableNode rightChild){
        this(title,leftChild,rightChild,CLI_PRINT_COLOR.BLACK);
    }

    public PrintableNodeInfo(String title, PrintableNode leftChild, PrintableNode righthild, CLI_PRINT_COLOR textColor){
        this.title = title;
        this.leftChild = leftChild;
        this.rightChild = righthild;
        this.textColor = textColor;
    }

    public String getTitle(){
        return title;
    }

    public CLI_PRINT_COLOR getTextColor(){
        return textColor;
    }

    public String getTitleFormatted(int max_chars){
        return this.textColor+title+CLI_PRINT_COLOR.RESET;
        /*
        String title = this.title.length() > max_chars ? this.title.substring(0,max_chars+1):this.title;
        boolean left = true;
        while(title.length() < max_chars){
            if (left){
                title = " "+title;
            } else {
                title = title + " ";
            }
        }
        return this.textColor+title+CLI_PRINT_COLOR.RESET;*/
    }

    public int getTitleLength(){
        return title.length();
    }

    public PrintableNodeInfo getLeftChildInfo(){
        if (leftChild == null){
            return null;
        }
        return leftChild._getPrintableNodeInfo();
    }

    public PrintableNodeInfo getRightChildInfo(){
        if (rightChild == null){
            return null;
        }
        return rightChild._getPrintableNodeInfo();
    }
}

Clase NodePosition

package com.tomac120.NodePrinter;

/**
 * Created by elijah on 6/28/16.
 */
public class PrintableNodePosition implements Comparable<PrintableNodePosition> {
    public final int row;
    public final int column;
    public final PrintableNodeInfo nodeInfo;
    public PrintableNodePosition(PrintableNodeInfo nodeInfo, int row, int column){
        this.row = row;
        this.column = column;
        this.nodeInfo = nodeInfo;
    }

    @Override
    public int compareTo(PrintableNodePosition o) {
        return Integer.compare(this.column,o.column);
    }
}

Y, finalmente, interfaz de nodo

package com.tomac120.NodePrinter;

/**
 * Created by elijah on 6/28/16.
 */
public interface PrintableNode {
    PrintableNodeInfo _getPrintableNodeInfo();
    PrintableNode _getLeftChild();
    PrintableNode _getRightChild();
}
user1122069
fuente
0

Una solución Scala, adaptada de la respuesta de Vasya Novikov y especializada para árboles binarios:

/** An immutable Binary Tree. */
case class BTree[T](value: T, left: Option[BTree[T]], right: Option[BTree[T]]) {

  /* Adapted from: http://stackoverflow.com/a/8948691/643684 */
  def pretty: String = {
    def work(tree: BTree[T], prefix: String, isTail: Boolean): String = {
      val (line, bar) = if (isTail) ("└── ", " ") else ("├── ", "│")

      val curr = s"${prefix}${line}${tree.value}"

      val rights = tree.right match {
        case None    => s"${prefix}${bar}   ├── ∅"
        case Some(r) => work(r, s"${prefix}${bar}   ", false)
      }

      val lefts = tree.left match {
        case None    => s"${prefix}${bar}   └── ∅"
        case Some(l) => work(l, s"${prefix}${bar}   ", true)
      }

      s"${curr}\n${rights}\n${lefts}"

    }

    work(this, "", true)
  }
}
Colin Woodbury
fuente
Por cierto, también he decidido publicar una solución Scala: stackoverflow.com/a/43348945/1091436
VasiliNovikov
0

Ver también estas respuestas .

En particular, no fue demasiado difícil usar abego TreeLayout para producir los resultados que se muestran a continuación con la configuración predeterminada.

Si prueba esa herramienta, tenga en cuenta esta advertencia: imprime los niños en el orden en que se agregaron. Para un BST donde las cuestiones de izquierda a derecha importan, encontré que esta biblioteca es inapropiada sin modificaciones.

Además, el método para agregar hijos simplemente toma un nodo parenty childcomo parámetros. (Por lo tanto, para procesar un grupo de nodos, debe tomar el primero por separado para crear una raíz).

Terminé usando esta solución anterior, modificándola para incluir el tipo <Node>para tener acceso a Nodelos lados izquierdo y derecho (secundarios).

árbol creado con abego TreeLayout

TT--
fuente
0

Aquí hay otra forma de visualizar su árbol: guarde los nodos como un archivo xml y luego deje que su navegador le muestre la jerarquía:

class treeNode{
    int key;
    treeNode left;
    treeNode right;

    public treeNode(int key){
        this.key = key;
        left = right = null;
    }

    public void printNode(StringBuilder output, String dir){
        output.append("<node key='" + key + "' dir='" + dir + "'>");
        if(left != null)
            left.printNode(output, "l");
        if(right != null)
            right.printNode(output, "r");
        output.append("</node>");
    }
}

class tree{
    private treeNode treeRoot;

    public tree(int key){
        treeRoot = new treeNode(key);
    }

    public void insert(int key){
        insert(treeRoot, key);
    }

    private treeNode insert(treeNode root, int key){
        if(root == null){
            treeNode child = new treeNode(key);
            return child;
        }

        if(key < root.key)
            root.left = insert(root.left, key);
        else if(key > root.key)
            root.right = insert(root.right, key);

        return root;
    }

    public void saveTreeAsXml(){
        StringBuilder strOutput = new StringBuilder();
        strOutput.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        treeRoot.printNode(strOutput, "root");
        try {
            PrintWriter writer = new PrintWriter("C:/tree.xml", "UTF-8");
            writer.write(strOutput.toString());
            writer.close();
        }
        catch (FileNotFoundException e){

        }
        catch(UnsupportedEncodingException e){

        }
    }
}

Aquí hay un código para probarlo:

    tree t = new tree(1);
    t.insert(10);
    t.insert(5);
    t.insert(4);
    t.insert(20);
    t.insert(40);
    t.insert(30);
    t.insert(80);
    t.insert(60);
    t.insert(50);

    t.saveTreeAsXml();

Y la salida se ve así:

ingrese la descripción de la imagen aquí

usuario4617883
fuente
0
using map...
{
Map<Integer,String> m = new LinkedHashMap<>();

         tn.printNodeWithLvl(node,l,m);

        for(Entry<Integer, String> map :m.entrySet()) {
            System.out.println(map.getValue());
        }
then....method


   private  void printNodeWithLvl(Node node,int l,Map<Integer,String> m) {
       if(node==null) {
           return;
       }
      if(m.containsKey(l)) {
          m.put(l, new StringBuilder(m.get(l)).append(node.value).toString());
      }else {
          m.put(l, node.value+"");
      }
      l++;
      printNodeWithLvl( node.left,l,m);
      printNodeWithLvl(node.right,l,m);

    }
}
satish
fuente
0

Esta es una de las versiones más simples que podría implementar. Espero que te ayude

class Node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None

    def add(self, data):

        if data < self.data:
            if self.left is None:
                self.left = Node(data)
            else:
                self.left.add(data)
        if data > self.data:
            if self.right is None:
                self.right = Node(data)
            else:
                self.right.add(data)

    def display(self):
        diff = 16
        start = 50
        c = ' '

        this_level = [(self, start)]

        while this_level:
            next_level = list()
            last_line = ''

            for node, d in this_level:
                line = last_line + c*(d - len(last_line)) + str(node.data)
                print(line, end='\r')
                last_line = line

                if node.left:
                    next_level.append((node.left, d - diff))
                if node.right:
                    next_level.append((node.right, d + diff))
                this_level = next_level
                diff = max(diff//2, 2)
            print('\n')


if __name__ == '__main__':
    from random import randint, choice
    values = [randint(0, 100) for _ in range(10)]
    bst = Node(choice(values))
    for data in values:
        bst.add(data)

    bst.display()

sourabh gupta
fuente