191 votes

Comment imprimer un diagramme d'arbre binaire en Java ?

Comment puis-je imprimer un arbre binaire en Java de sorte que la sortie soit comme :

   4 
  / \ 
 2   5 

Mon nœud :

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

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

6 votes

C'est une question délicate. Je pense que vous devez d'abord déterminer la profondeur de l'arbre. Personnellement, je déverserais simplement le graphe de nœuds dans Graphviz et le laisserais s'en occuper :-)

0 votes

Il semble que si vous aviez beaucoup d'éléments, l'élément racine aurait un ÉNORME avantage à partir de lui.

0 votes

J'ai une méthode getDept() dans l'arbre

309voto

Vasya Novikov Points 1670

Imprimer un [grand] arbre par lignes.

exemple de sortie :

z
 c
    a
    b
 d
 e
    asdf
 f

code :

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 + "    ");
            }
        }
    }
}

P.S. Cette réponse ne se concentre pas exactement sur les arbres "binaires" - au lieu de cela, elle imprime toutes sortes d'arbres. La solution est inspirée de la commande "tree" de linux.

0 votes

Cette solution permet-elle de traiter les arbres binaires à angle droit ?

0 votes

@VasyaNovikov comment réécririez vous le texte ? children.get(children.size() - 1) si HashMap a été utilisé pour les enfants ? J'ai réussi à modifier toutes les autres parties sauf celle-ci.

0 votes

@LeNguyenDuyAnh quelle est la signature de type proposée par HashMap ? HashMap<String, List<String>> ?

262voto

michal.kreuzman Points 3214

J'ai créé une simple imprimante à arbre binaire. Vous pouvez l'utiliser et la modifier comme vous le souhaitez, mais elle n'est pas optimisée de toute façon. Je pense que beaucoup de choses peuvent être améliorées ici ;)

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

}

Sortie 1 :

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

Sortie 2 :

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

1 votes

Comment convertir cette sortie en horizontal ?

0 votes

Pour une sortie horizontale, il est préférable d'utiliser la solution de Vasya Novikov.

3 votes

Ce serait bien si vous pouviez développer le choix de 2^n - 1 comme premiers espaces et 2^(n+1) - 1 comme espaces intermédiaires.

43voto

Laurent Demailly Points 111
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 ? " |      " : "        "));
        }
    }

}

s'imprimera :

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

pour l'entrée

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

il s'agit d'une variante de la réponse de @anurag - les |s supplémentaires me gênaient.

1 votes

Ce serait génial si tu pouvais le faire pivoter de 90°.

17voto

Anurag Agarwal Points 63

Michal.kreuzman Bien joué, je dois dire. C'était utile.

Toutefois, la méthode ci-dessus ne fonctionne que pour les chiffres simples : si vous utilisez plus d'un chiffre, la structure sera mal placée puisque vous utilisez des espaces et non des tabulations.

Pour mes codes ultérieurs, j'avais besoin de plus de chiffres que 2, alors j'ai créé un programme moi-même.

Il a quelques bogues maintenant, encore une fois en ce moment je me sens paresseux pour les corriger mais il imprime très bien et les noeuds peuvent prendre un plus grand nombre de chiffres.

L'arbre ne sera pas comme le mentionne la question mais il est tourné de 270 degrés :)

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

Placez cette fonction avec votre propre TreeNode spécifié et gardez le niveau initialement 0, et profitez-en !

Voici quelques exemples de résultats :

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

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

Le seul problème est l'extension des branches ; je vais essayer de résoudre le problème dès que possible mais en attendant vous pouvez l'utiliser aussi.

16voto

hd42 Points 514

Votre arbre aura besoin de deux fois la distance pour chaque couche :

       a
      / \\
     /   \\
    /     \\
   /       \\
   b       c
  / \\     / \\
 /   \\   /   \\
 d   e   f   g
/ \\ / \\ / \\ / \\
h i j k l m n o

Vous pouvez enregistrer votre arbre dans un tableau de tableaux, un tableau pour chaque profondeur :

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

Si votre arbre n'est pas complet, vous devez inclure des valeurs vides dans ce tableau :

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

Ensuite, vous pouvez itérer sur le tableau pour imprimer votre arbre, en imprimant des espaces avant le premier élément et entre les éléments selon la profondeur et en imprimant les lignes selon que les éléments correspondants dans le tableau pour la couche suivante sont remplis ou non. Si vos valeurs peuvent avoir plus d'un caractère, vous devez trouver la valeur la plus longue en créant la représentation du tableau et multiplier toutes les largeurs et le nombre de lignes en conséquence.

1 votes

Et si l'arbre n'est pas complet ? Dans ce cas, il semble que vous devriez être en mesure de le faire sans doubler l'espace à chaque niveau.

0 votes

Oui, mais seulement dans certains cas très limités où la plupart des sous-arbres sont des listes liées au lieu d'arbres du même niveau vers le bas, ou vous dessineriez différents sous-arbres avec un espacement différent entre les couches...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X