Language agnostic 如何以良好的格式打印出一棵树?

Language agnostic 如何以良好的格式打印出一棵树?,language-agnostic,data-structures,tree,Language Agnostic,Data Structures,Tree,打印树结构中的树的最简单方法是什么?比如 some root / | \ child1 child2 child 3 / anotherchild / \ yup another 甚至手工格式化也很困难。如何让程序以这种方式打印树?好吧,您可以尝试类

打印树结构中的树的最简单方法是什么?比如

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

甚至手工格式化也很困难。如何让程序以这种方式打印树?

好吧,您可以尝试类似PHP的var_dump的东西-如果您在类似树的数组上尝试var_dump,它将为您提供该树的公平表示,即:

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

虽然我自己没有尝试过,但它有一个纯文本。

除非有一些好的图形库可供使用,否则用您描述的方式表示层次结构会有很多困难

假设要将其打印到控制台或文件,则必须预先计算整个树中所有数据元素的长度,以便正确排列它们。你如何处理像换行这样的事情

更好的方法是垂直表示树,使用缩进显示子元素

Root
    - Child1
        - Grandchild1
        - Grandchild2
    - Child2
        - Grandchild3
        - Grandchild4
这对于编码来说要简单得多,而且对于换行这样的事情也更宽容——因为一行中只有一个元素。这就是文件夹浏览器或xml文档显示其分层数据的方式

要这样做,请执行深度优先遍历,然后在递归步骤之前打印出节点:

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

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

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

来个类似的问题怎么样? 它打印了一个漂亮的ASCII艺术树


或者,如果你想完全图形化的话?

我去年不得不写一个家谱应用程序。我在网上找到了一个java教程,这很有帮助,但我的Google fu今天让我失望了,所以我只能简单地解释一下

它只是一种基于子节点调整父节点位置的递归算法。在伪代码中是这样的:

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

我可能记不清这一点,您可能需要稍微调整代码以使其正确。

以下答案是用java编写的,但它非常简单,可以轻松地转录到其他语言:

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

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

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

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

private static <T> void dumpRecursive( T node, String parentPrefix,
        Function1<List<T>,T> breeder, Function1<String,T> stringizer,
        Procedure1<String> emitter )
{
    for( Iterator<T> iterator = breeder.invoke( node ).iterator(); iterator.hasNext(); )
    {
        T childNode = iterator.next();
        String[] prefixes = PREFIXES[iterator.hasNext()? 0 : 1];
        emitter.invoke( parentPrefix + prefixes[0] + stringizer.invoke( childNode ) );
        dumpRecursive( childNode, parentPrefix + prefixes[1], breeder, stringizer, emitter );
    }
}
…如果使用以下示例程序调用它:

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

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

    public static void main( String[] args )
    {
        Node tree = new Node( "Automobile",
                new Node( "Passenger Vehicle",
                        new Node( "Light Passenger Vehicle",
                                new Node( "Two Wheeled",
                                        new Node( "Moped" ),
                                        new Node( "Scooter" ),
                                        new Node( "Motorcycle" ) ),
                                new Node( "Three Wheeled" ),
                                new Node( "Four Wheeled",
                                        new Node( "Car" ),
                                        new Node( "Station Wagon" ),
                                        new Node( "Pick-up Truck" ),
                                        new Node( "Sports Utility Vehicle" ) ) ),
                        new Node( "Heavy Passenger Vehicle",
                                new Node( "Bus",
                                        new Node( "Single-Deck Bus",
                                                new Node( "Mini Bus" ),
                                                new Node( "Big Bus" ) ),
                                        new Node( "Double-Deck Bus" ) ),
                                new Node( "Coach",
                                        new Node( "Deluxe" ),
                                        new Node( "Air-Conditioned" ) ) ) ),
                new Node( "Goods Vehicle",
                        new Node( "Light Goods Vehicle",
                                new Node( "Delivery Van" ),
                                new Node( "Light Truck" ),
                                new Node( "Tempo",
                                        new Node( "Three Wheeler Tempo" ),
                                        new Node( "Four Wheeler Tempo" ) ) ),
                        new Node( "Heavy Goods Vehicle",
                                new Node( "Truck" ),
                                new Node( "Tractor Trailer" ) ) ) );
        dump( tree, n -> n.children, n -> n.name, s -> System.out.println( s ) );
    }
}
final class Scratch
{
静态类节点
{
字符串名;
列出儿童名单;
节点(字符串名称、节点…子节点)
{
this.name=名称;
this.children=Arrays.asList(children);
}
}
公共静态void main(字符串[]args)
{
节点树=新节点(“汽车”,
新节点(“乘用车”,
新节点(“轻型乘用车”,
新节点(“两轮”,
新节点(“轻便摩托车”),
新节点(“指示器”),
新节点(“摩托车”),
新节点(“三轮”),
新节点(“四轮”,
新节点(“Car”),
新节点(“旅行车”),
新节点(“皮卡”),
新节点(“运动型多用途车”),
新节点(“重型乘用车”,
新节点(“总线”,
新节点(“单层总线”,
新节点(“迷你巴士”),
新节点(“大总线”),
新节点(“双层巴士”),
新节点(“Coach”,
新节点(“豪华”),
新节点(“空调”),
新节点(“货车”,
新节点(“轻型货车”,
新节点(“送货车”),
新节点(“轻型卡车”),
新节点(“节奏”,
新节点(“三轮车节奏”),
新节点(“四轮节奏”),
新节点(“重型货车”,
新节点(“卡车”),
新节点(“牵引拖车”);
转储(树,n->n.children,n->n.name,s->System.out.println(s));
}
}

您肯定会将缩进深度作为第二个参数传递给
PrintNode
(客户端调用默认为0,并在递归调用中添加一个级别)?这样就不必手动递减。这对于以请求的格式打印树是没有用的。@Zecc-这就是我最后一句话的意思(在我的示例之后)。我试图用一种语言不可知的方式来写它,但没有具体说明缩进或打印是如何实际完成的。实际上,我通常会有一个公共调用,它调用一个带有0的私有重写来对使用者隐藏它。@Paul Creasy-你明白了-用行表示树比用列表示树容易得多。您正在打印的数据元素的长度可能会导致各种不对齐。控制台上的列限制也会出现问题。我认为答案仍然有用。我甚至不愿意按照问题指定的方式打印出来。@Zecc-好的,我已经添加了你的版本。现在我在看它,我认为我原来的简化是不必要的,后一种方法已经足够清楚了。:-)您应该更改语言不可知标记,因为有些语言/环境是本机实现的。很好!我曾经编写过一个名为的小库,它可以生成Java中的树。
final class Scratch
{
    static class Node
    {
        String name;
        List<Node> children;

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

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