我如何在Java中打印一个二叉树,这样输出就像:

   4 
  / \ 
 2   5 

我的节点:

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

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

当前回答

这是水平视图最简单的解决方案。我举了很多例子。很适合我的目的。更新自@ ntin -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

其他回答

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回答的一个变体——看到额外的|让我很烦

我发现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

我为此做了一个改进的算法,可以很好地处理不同大小的节点。它使用行自上而下地打印。

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

要在树中使用它,让Node类实现PrintableNode。

示例输出:

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

我需要在我的一个项目中打印一个二叉树,为此我准备了一个java类TreePrinter,其中一个示例输出是:

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

下面是TreePrinter类和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));
    }
}

迈克尔。克鲁兹曼,我不得不说,这人不错。这很有用。

然而,上面的方法只适用于个位数:如果您要使用多个数字,结构将会错位,因为您使用的是空格而不是制表符。

至于我后来的代码,我需要更多的数字,所以我自己编写了一个程序。

它现在有一些bug,现在我感觉很懒去纠正它们,但它打印得非常漂亮,节点可以接受更大数量的数字。

这棵树不会像问题提到的那样,但它旋转了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

唯一的问题是延伸的分支;我会尽快解决这个问题,但在此之前你也可以使用它。