이진 트리 다이어그램을 인쇄하는 방법?


163

출력이 다음과 같이되도록 Java로 이진 트리를 인쇄하는 방법은 무엇입니까?

   4 
  / \ 
 2   5 

내 노드 :

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

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

5
까다로운 일입니다. 먼저 나무의 깊이를 결정해야한다고 생각합니다. 개인적으로 노드 그래프를 graphviz에 덤프하고 처리하도록했습니다. :-)
Omnifarious

많은 요소가 있다면 루트 요소는 거대한 가장자리를 가져옵니다.

트리에 getDept () 메소드가 있습니다
Tian

1
아이디어가 나를 즐겁게하기 때문에 C ++로 코드를 작성하고 graphviz digraph 형식을 뱉어 냈습니다. 아름답게 포맷 된 나무.
Omnifarious

답변:


238

간단한 이진 트리 프린터를 만들었습니다. 원하는대로 사용하고 수정할 수 있지만 어쨌든 최적화되지 않았습니다. 나는 여기에 많은 것들이 향상 될 수 있다고 생각합니다.)

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

}

출력 1 :

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

출력 2 :

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

1
이 출력을 가로로 변환하는 방법?
jijesh Aj

수평 출력의 경우 Vasya Novikov의 솔루션을 사용하는 것이 좋습니다.
michal.kreuzman

3
첫 번째 공백으로 2 ^ n-1을 선택하고 공백 사이를 2 ^ (n + 1)-1로 선택하는 것이 좋을 것입니다.
DJ '

오른쪽으로 치우친 15 개 값의 나무 중 하나에 대해 시도했지만 인쇄물을 보는 것은 매우 관리하기 힘들어 균형 잡힌 나무에 좋습니다.
akhil_mittal

3
내 트리의 깊이는 44 레이어이므로 8796093022207 공백을 인쇄하려고하면 Java가 충돌합니다. 따라서 경고하십시오.
CX gamer

287

[큰] 나무를 한 줄씩 인쇄하십시오.

출력 예 :

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

암호:

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

추신이 답변은 "이진"나무에 초점을 맞추지 않고 모든 종류의 나무를 인쇄합니다. 해결책은 리눅스의 "tree"명령에서 영감을 얻은 것입니다.


이 솔루션은 오른쪽으로 기울어 진 이진 트리를 처리합니까?
patentfox

@VasyaNovikov children.get(children.size() - 1)HashMap이 어린이들에게 사용된다면 어떻게 다시 쓰겠 습니까? 나는 다른 모든 부분을 수정했습니다.
Le Nguyen Duy Anh

@LeNguyenDuyAnh HashMap이 제안한 형식 서명은 무엇입니까? HashMap<String, List<String>>?
VasiliNovikov

로 트리를 구현했습니다 HashMap<String, Node>. 문자열은 노드의 ID입니다.
Le Nguyen Duy Anh

실제로 text-tree 라는 작은 Java 라이브러리에서 비슷한 것을 구현했습니다 . 어쩌면 누군가를 도울 수 있습니다.
barfuin

47

나는 이것을 위해 향상된 크기의 알고리즘을 만들었습니다. 줄을 사용하여 하향식으로 인쇄합니다.

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

이것을 Tree에 사용하려면 Node클래스를 구현하십시오 PrintableNode.

출력 예 :

                                         2952:0                                             
                    ┌───────────────────────┴───────────────────────┐                       
                 1249:-1                                         5866:0                     
        ┌───────────┴───────────┐                       ┌───────────┴───────────┐           
     491:-1                  1572:0                  4786:1                  6190:0         
  ┌─────┘                                               └─────┐           ┌─────┴─────┐     
339:0                                                      5717:0      6061:0      6271:0   

"선택된 답변"기술을 복제하려고했습니다. 그러나 나는 이것이 가장 좋은 대답이라고 생각합니다. 견고하고 간결합니다.
Vikrant Goel

이것을 구현 한 후에는 훌륭하게 작동하지만 균형 잡힌 나무에 대해서만 작동합니다. 불균형이 있으면 이상한 결과가 반환됩니다.
mitbanip

내가 얻을 ???????????대신 노드 사이의 라인 만 좀 UTF8 ANS 물건의 문제가 될 것이다. 어쨌든, 좋은 말입니다. 정말 사용하기 쉽기 때문에 가장 좋은 대답입니다.
Fitz

그렇습니다. 줄과 공백 단락 의 모든 특수 문자를 변경해야했습니다 .
Fitz

멋지게 , 요소 배열 인쇄를 지원하기 위해 트리를 인쇄하기 위해 @MightyPork 논리를 사용하여 요점 을 만드는 요점 을 만들었습니다 . 참조public static <T> void print(T[] elems)
네오

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

}

인쇄합니다 :

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

입력

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

이것은 @anurag의 답변에서 변형 된 것입니다.


90도 회전하면 멋질 것입니다.
Abhijit Sarkar

34

에서 적응 Vasya Novikov 보낸 사람대답하는 것이 더 만들기 위해 바이너리 및을 사용 StringBuilder효율 (합치 String자바에서 함께 오브젝트은 일반적으로 비효율적이다).

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

산출:

       ┌── 7
   ┌── 6
      └── 5
└── 4
       ┌── 3
    └── 2
        └── 1
            └── 0

BST에 30,40,50,60,70,80 값을 삽입하면 트리에서 작동하지 않습니다. 그것은 오른쪽으로 치우친 나무를 만듭니다. right != null편집 할 때 isTail의 값은 false이어야합니다 . 편집하고 테스트했는데 정상적으로 작동합니다.
akhil_mittal

입력 해 주셔서 감사합니다. 방금 답변을 편집했습니다.
토드 데이비스

@Vasya Novikov의 답변은 훌륭하지만 링크 목록 버전이 필요하며 귀하의 답변은 제 경우에 맞습니다.
hychou

모든 대답에서 이것은 가장 잘 보이는 트리를 생성하며 코드는 매우 깨끗합니다!
p-sun

15

michal.kreuzman 좋은 말 하나.

나는 이것이 스스로 도움이되는 것을 발견했을 때 스스로 프로그램을 만들고 그물에 코드를 검색하는 게으른 느낌이었습니다.

그러나 공백이 아닌 탭을 사용하지 않고 구조가 잘못 배치되고 프로그램의 사용이 느슨해지기 때문에 두 자리 이상을 사용하는 것처럼 한 자리에서만 작동한다는 것을 두려워합니다.

내 나중에 코드에 관해서는 더 큰 입력이 필요했습니다 (적어도 10 이상).

그것은 지금 약간의 버그가 있습니다. 다시 한 번 나는 그것을 교정하는 게으른 느낌이 들지만 매우 아름답게 인쇄되고 노드는 큰 가치를 취할 수 있습니다.

나무는 질문에서 언급했듯이 270도 회전합니다. :)

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

이 기능을 사용자가 지정한 TreeNode와 함께 배치하고 처음에는 레벨을 0으로 유지하고 즐기십시오!

다음은 몇 가지 샘플 출력입니다.

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


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

문제는 확장 가지에만 있습니다. 최대한 빨리 문제를 해결하려고 노력하지만 그때까지도 사용할 수 있습니다.


14

나무는 각 레이어마다 두 배의 거리가 필요합니다.

       ㅏ
      / \
     / \
    / \
   / \
   기원전
  / \ / \
 / \ / \
 Defg
/ \ / \ / \ / \
Hijklmno

깊이에 따라 하나의 배열로 배열을 배열로 저장할 수 있습니다.

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

트리가 가득 차지 않은 경우 해당 배열에 빈 값을 포함해야합니다.

       ㅏ
      / \
     / \
    / \
   / \
   기원전
  / \ / \
 / \ / \
 Defg
/ \ \ / \ \
힐 크모
[[a], [b, c], [d, e, f, g], [h, i,, k, l, m,, o]]

그런 다음 배열을 반복하여 트리를 인쇄하고 첫 번째 요소 앞의 간격을 인쇄하고 깊이에 따라 요소 사이를 인쇄하고 다음 레이어에 대한 배열의 해당 요소가 채워 졌는지에 따라 선을 인쇄 할 수 있습니다. 값이 2자를 초과 할 수있는 경우 배열 표현을 작성하는 동안 가장 긴 값을 찾아 모든 너비와 행 수를 곱해야합니다.


나무가 완성되지 않으면 어떻게 되나요? 이 경우 각 레벨의 공간을 두 배로 늘리지 않고도이 작업을 수행 할 수 있어야합니다.
templatetypedef

예, 그러나 대부분의 하위 트리가 같은 수준의 나무 대신 링크 된 목록 인 경우 또는 레이어 간 간격이 다른 여러 하위 트리를 그리는 매우 제한된 경우에만 해당됩니다.
hd42

13

VasyaNovikov의 대답은 큰 일반 트리를 인쇄하는 데 매우 유용하며 이진 트리로 수정했습니다.

암호:

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

샘플 출력 :

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

8

Java로 쓴 것과 비슷한 Scala 언어 의 솔루션 :

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
    }

}

출력 예 :

vasya
├── frosya
   ├── petya
      └── masha
   └── kolya
└── frosya2

1
Lambda를 Java로도 사용할 수 있다면 Java 솔루션을 업데이트하고 싶습니까?
Tintin

@ 틴틴 스칼라는 단순히 람다 함수에 관한 것이 아닙니다. 그러나 Java에 대한 개선이 마음에
들었다

5

나는 여러분 모두가 훌륭한 해결책을 가지고 있음을 알고 있습니다. 나는 단지 내 것을 공유하고 싶을 수도 있습니다. 어쩌면 그것이 최선의 방법은 아니지만 나 자신에게 완벽합니다!

pythonpip에, 정말 아주 간단합니다! 팔!

Mac 또는 Ubuntu (mine은 mac)

  1. 터미널 열기
  2. $ pip install drawtree
  3. $python, python console을 입력하십시오. 다른 방법으로 할 수 있습니다
  4. from drawtree import draw_level_order
  5. draw_level_order('{2,1,3,0,7,9,1,2,#,1,0,#,#,8,8,#,#,#,#,7}')

끝난!

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

소스 추적 :

이 게시물을보기 전에 Google "이진 트리 일반 텍스트"

그리고 나는이 발견 https://www.reddit.com/r/learnpython/comments/3naiq8/draw_binary_tree_in_plain_text/을 이 날 직접, https://github.com/msbanik/drawtree


@DenysVitali 아 맞아) : 아마도 이것을 직렬화 된 레벨 순서 순회 (모든 언어 / 파이썬)에서 트리를 인쇄하는 방법으로 옮겨야합니다.
Sean L

3
무례하게 보이고 싶지 않았지만 사용자 java가 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   

2

이것은 트리를 인쇄하는 매우 간단한 솔루션입니다. 그렇게 예쁘지는 않지만 정말 간단합니다.

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

샘플 출력 :

      106
            105
104
            103
                  102
                        101
      100

2

VasyaNovikov 답변을 기반으로합니다. 일반 및 기능 인터페이스와 같은 일부 Java 마법으로 개선되었습니다.

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

초기 통화 예 :

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

같은 것을 출력합니다

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

2

Java로 이진 트리 프린터를 작성했습니다.

코드는 여기 GitHub에 있습니다 .

런타임 효율성에 최적화되지 않았지만 ASCII로 인쇄하는 것에 대해 이야기하고 있기 때문에 매우 큰 나무에서는 사용되지 않을 것이라고 생각했습니다. 그래도 멋진 기능이 있습니다.

  1. 큰 하위 트리가 가능한 한 작은 하위 트리 아래로 확장되므로 공간을 효율적으로 사용합니다.
  2. 노드 레이블 사이의 최소 수평 공간을 설정하는 매개 변수가 있습니다.
  3. 노드 레이블은 임의 길이의 문자열입니다.
  4. 단일 트리를 인쇄하는 방법 외에도 필요한 수의 행을 사용하여 페이지 전체에 가로로 트리 목록을 인쇄하는 방법 (페이지 너비에 대한 매개 변수 포함)이 있습니다.
  5. 대각선 분기 (슬래시 및 백 슬래시 문자 사용) 또는 가로 분기 (아스키 상자 그리기 문자 사용)가있는 트리를 인쇄하는 옵션이 있습니다. 후자는 더 콤팩트하며 트리 레벨을보다 선명하게 만듭니다.
  6. 효과가있다.

일부 데모 / 테스트 프로그램이 포함되어 있습니다.

프로그램에 의해 인쇄 된대로 임의로 생성 된 이진 트리의 예는 다음과 같습니다. 이것은 작은 왼쪽 하위 트리 아래에 큰 오른쪽 하위 트리가 확장되어 공간을 효율적으로 사용하는 방법을 보여줍니다.

             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                      

페이지에서 5 개의 노드 이진 트리 (순서 레이블이있는)를 모두 인쇄하는 예 :

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 

다음은 가로 간격이 1과 3, 대각선 및 가로 가지로 4 가지 방식으로 인쇄 된 동일한 나무의 예입니다.

                   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               

이 프로젝트를 게시 한 것이 좋습니다. 그것은 좋은 일을하는 것처럼 보이지만 기본적으로 라이브러리에 대한 링크는 스택 오버플로에 대한 좋은 대답을하지 않습니다. 최소한 라이브러리를 사용하여 제공 한 예제를 표시하는 데 필요한 코드를 포함해야 사람들이 라이브러리 사용과 관련된 내용을 알 수 있습니다. 지금은 GitHub 리포지토리에 대한 광고 일뿐입니다. 사람들에게 실제로 사용하는 방법을 보여 주면 나쁜 일이 아닙니다.
Makyen

BTW : 예제 코드에서 편집 @Makyen하는 경우 주석 에 포함시켜 여기에 ping하십시오 .
Makyen

2

이것은 흥미로운 질문이며, 프로젝트도 작성했습니다.

이진 트리 프린터

여기 몇 가지 예가 있어요.

무작위 BST를 인쇄하십시오.

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     

leetcode 스타일 레벨 순서 배열에서 트리를 인쇄합니다. '#'은 아래에 노드가없는 경로 종결자를 의미합니다.

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

1

내 프로젝트 중 하나에서 이진 트리를 인쇄해야했습니다 .Java 클래스를 준비했기 TreePrinter때문에 샘플 출력 중 하나는 다음과 같습니다.

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

다음은 class TreePrinter와 함께 class 코드입니다 TextNode. 모든 트리를 인쇄하려면 TextNode클래스를 사용하여 동등한 트리를 만들면 됩니다.


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

마지막으로 다음은 주어진 샘플을 인쇄하기위한 테스트 클래스입니다.


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

1

애플릿을 사용하여이를 쉽게 시각화 할 수 있습니다. 다음 항목을 인쇄해야합니다.

  1. 반경이 보이는 원으로 노드를 인쇄합니다

    • 각 노드의 좌표를 가져옵니다.

    • x 좌표는 노드가 순회 순회에 방문하기 전에 방문한 노드 수로 시각화 할 수 있습니다.

    • y 좌표는 특정 노드의 깊이로 시각화 할 수 있습니다.


  1. 부모와 자녀 사이의 선을 인쇄하십시오

    • 이는 노드와 각 노드의 부모의 x 및 y 좌표를 별도의 목록으로 유지하여 수행 할 수 있습니다.

    • 루트를 제외한 각 노드에 대해 자식과 부모의 x 및 y 좌표를 취하여 각 노드를 부모와 연결합니다.


기존 답변보다 시각화하여 더 나은 솔루션을 제공 할 수 있습니까?
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

1 ~ 2 자리 정수에서만 작동합니다 (제네릭으로 만들려면 게으른했습니다)

비뚤어진 완전한


1

이것은 가로보기를위한 가장 간단한 솔루션이었습니다. 많은 예제로 시도했습니다. 내 목적에 잘 맞습니다. @ 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);
    }
}

요구:

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

해결책:

                         |-- 80
                    |-- 70
               |-- 60
          |-- 50
     |-- 40
|-- 30
     |-- 20
          |-- 10

1
  1. 트래버스수평으로 정렬 해야합니다. 당신의 나무.
  2. 노드 길이공간 길이를 선택하십시오 .
  3. 레벨 을 기준으로 트리의 기본 너비를 구합니다 .node_length * nodes_count + space_length * spaces_count*
  4. 분기, 간격, 들여 쓰기 및 계산 된 기본 너비 사이의 관계를 찾으십시오.

GitHub의 코드 : YoussefRaafatNasry / bst-ascii-visualization

                                             07                     
                                             /\                     
                                            /  \                    
                                           /    \                   
                                          /      \                  
                                         /        \                 
                                        /          \                
                                       /            \               
                                      /              \              
                                     /                \             
                                    /                  \            
                                   /                    \           
                                 03                      11         
                                 /\                      /\         
                                /  \                    /  \        
                               /    \                  /    \       
                              /      \                /      \      
                             /        \              /        \     
                           01          05          09          13   
                           /\          /\          /\          /\   
                          /  \        /  \        /  \        /  \  
                        00    02    04    06    08    10    12    14

코드가 짧아서 답변에 포함시킬 수 있다고 말하고 싶습니다.
m02ph3u5

코드는 단순한 visualize함수 가 아니라 visualizer헤더 파일을 포함하여 약 200 위치 의 전체 클래스입니다.
YoussefRaafatNasry

1

녹 솔루션을 찾는 사람들을 위해 :

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

출력은 다음과 같습니다.

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

0

콘솔에서 인쇄 :

                                                500
                       700                                             300   
    200                                   400                                                                                          

간단한 코드 :

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

    }

0

다음은 매우 다양한 트리 프린터입니다. 가장 잘 보이지는 않지만 많은 경우를 처리합니다. 알아낼 수 있다면 슬래시를 추가하십시오. 여기에 이미지 설명을 입력하십시오

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

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

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

마지막으로 노드 인터페이스

package com.tomac120.NodePrinter;

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

0

Vasya Novikov의 답변에서 채택되었으며 이진 트리에 특화된 스칼라 솔루션 :

/** 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)
  }
}

BTW, 나도 스칼라 솔루션을 게시하기로 결정했습니다 : stackoverflow.com/a/43348945/1091436
VasiliNovikov

0

이 답변 도 참조하십시오 .

특히 abego TreeLayout 을 사용 하여 기본 설정으로 아래에 표시된 결과를 생성 하는 것은 그리 어렵지 않았습니다 .

해당 도구를 사용하는 경우 다음주의 사항에 유의하십시오. 추가 된 순서대로 하위 항목을 인쇄합니다. 왼쪽 대 오른쪽 문제가있는 BST의 경우이 라이브러리가 수정없이 부적절하다는 것을 알았습니다.

또한 자식을 추가하는 방법은 단순히 a parentchildnode를 매개 변수로 사용합니다. (따라서 많은 노드를 처리하려면 루트를 만들려면 첫 번째 노드를 별도로 가져와야합니다.)

나는 위의 솔루션 을 사용하여 왼쪽과 오른쪽 (자식)에 <Node>액세스 할 수 있도록 유형을 가져 가도록 수정했습니다 Node.

abego로 생성 된 트리


0

트리를 시각화하는 또 다른 방법은 다음과 같습니다. 노드를 xml 파일로 저장 한 다음 브라우저에 계층 구조가 표시되도록합니다.

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){

        }
    }
}

테스트하는 코드는 다음과 같습니다.

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

결과는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오


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

    }
}

0

이것은 내가 구현할 수있는 가장 간단한 버전 중 하나입니다. 나는 그것이 당신을 돕기를 바랍니다

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()

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.