Java:如何递归填充树节点

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java:如何递归填充树节点相关的知识,希望对你有一定的参考价值。

对于一个项目,我想生成一个树结构,它有x个子节点并且是n'层'深。最好在下图中描述一个层:

                  0
           1            1
        2     2      2     2

每行的数字等于图层编号。

我得到了以下名为Node的类:

public class Node {

    private String nodeName;
    private List<Node> children;
    private int layer;

    /**
     * A node with a name and a list of children on a given layer in a tree or
     * web
     *
     * @param nodeName the name of the node
     * @param children the list of children of this node
     * @param layer the layer in which this node exists
     */
    public Node(String nodeName, List<Node> children, int layer) {
        this.nodeName = nodeName;
        this.children = children;
        this.layer = layer;
    }
}

另外,我有每个领域的getter和setter。

经过两个完整的晚上,我想出了这个代码:

private static Node createTree() {
        Node masterNode = new Node();
        int childsPerNode = 3;
        int amountOfLayers = 5; //meaning 6 layers, 0 is included
        //Output = 364
        int totalNodeAmount = calculateNodeAmount(childsPerNode, amountOfLayers);

        //Loop for each layer, form bottom to top
        for (int currentLayer = 5; currentLayer > amountOfLayers; currentLayer--) {
            /**
             * For each layer, calculate the nodes for this layer, add children
             * to each node
             */
            int nodesThisLayer = calculateNodeAmount(childsPerNode, amountOfLayers) - calculateNodeAmount(childsPerNode, currentLayer);
            for (int nodeCount = 0; nodeCount < nodesThisLayer; nodeCount++) {
                List<Node> children = new ArrayList<>();
                for (int childCount = 0; childCount < childsPerNode; childCount++) {
                    String childFunctionName = "name";
                    Node childNode = new Node(childFunctionName, null, currentLayer);
                    children.add(childNode);
                }
                String parentFunctionName = "parent name";
                Node parentNode = new Node(parentFunctionName, children, currentLayer);
            }

        }
        return masterNode;
    }

关于我最终得到一个包含整个树的子节点的方法的任何帮助都非常感谢,因为我没有想法。我没有找到一个有x子和n层(或深度)的树的良好来源,因此我的潜在双重问题。

亲切的问候!

编辑:根据词典的评论,我想出了这个功能:

 private static void createTree(Node currentNode, int childrenPerNode, int numberOfLayers) {
    if (numberOfLayers == 0) {
        //Something is off here
        return;
    } else if (numberOfLayers > 0) {
        //Create sub nodes
        List<Node> nodes = new ArrayList<>();
        for (int i = 0; i < childrenPerNode; i++) {
            Node childNode = new Node("name", nodes, numberOfLayers);
            nodes.add(childNode);
        }
        //Add the children to the current node
        currentNode.setChilderen(nodes);
        for (int i = 0; i < childrenPerNode; i++) {
            //For each of the children per node, call this function again until the number of layers equals zero
            createTree(currentNode.getChildren().get(i), childrenPerNode, numberOfLayers - 1);
        }
    }

然而,这确实继续过于“太深”(太多层)循环。我为什么会这样想。

我现在正在寻找其他答案。谢谢你的时间!

答案

标题说“递归”,所以我假设你真的想写一个递归方法。要写一个,你必须学会​​递归思考。

对于构建树木的任务,这非常简单。树是递归定义的:树可以是空的,或者树是子节点的节点。

在你的情况下,定义有点复杂。层N树可以是空的(如果N大于或等于最大期望层数),或者它是具有层数N的节点和具有层数N + 1的K个子树。

这转换为算法:

Node buildTree(int N) {
  // A layer N tree may be empty (if N is more than the max desired layer number)
  if (L >= maxLayerNumber) {
    return new Node with no children
  }
  // ... or else it's a node with layer number N and K subtrees with layer number N+1
  Let C be an initially empty list of children
  for i = 1 to K {
    Let c = buildTree(N + 1)  
    Add c to C
  }
  return new Node with layer number N and children C
}

要获得整棵树,请致电buildTree(0)

我故意不提供Java代码。自己解决问题很重要。

另一答案

您可能希望避免通过使用注释中建议的递归或通过迭代树的底部节点并将它们保存在单独的集合中来计算您需要创建的子项数。

List<Node> children = new ArrayList<Node>(); 
children.add(masterNode);
int layer = amountOfLayers;

while (layer > 0) {
  List<Node> allBottomChildren = new ArrayList<Node>();
  for (Node child : children) {
    List<Node> nextLevelChildren = new ArrayList<Node>();
    for (int i = 0;i<childsPerNode;i++) {
      Node node = new Node("name", new ArrayList<Node>(), layer - 1);
      nextLevelChildren.add(node);
    }
    child.setChildren(nextLevelChildren);
    allBottomChildren.addAll(nextLevelChildren);
  }
  children = allBottomChildren;
  layer = layer - 1;
}
另一答案

这显然不是最好的设计,而是一个非常简短的解决方案:

int childsPerNode = 3;
int amountOfLayers = 5;

class AutoNode {

    int layer;
    List <AutoNode> childs;

    public AutoNode (int n) {
        layer = n;
        if (layer < amountOfLayers) {
            childs = new ArrayList<AutoNode> ();

            for (int i = 0; i < childsPerNode; ++i) {
                childs.add (new AutoNode (n + 1));
            }
        }
    }
    public String toString () {return ("layer: " + layer + " <" + ((layer < 5) ? childs.toString () : "()") + ">" );}
}

AutoNode root = new AutoNode (0);

界限:

int childsPerNode = 3;
int amountOfLayers = 5;

与节点有些陌生。但它可以作为第一个快速原型。

您可以向Autonode添加方法,并执行不同的练习。您可以将它们作为最终静态放入Autonode定义中。

如果要加热系统,请使用= new AutoNode(-40)调用root;但先计算3 ^ 45。

另一答案

这是一个完全封装的面向对象设计(即递归构造函数)的示例:

public class Tree
{
    private int layer;
    private int nodeID;
    private List<Tree> children;

    public Tree(int numOfchildren, int numOfLayers)
    {
        this(numOfchildren, numOfLayers, 0, new int[1]);
    }

    private Tree(int numOfchildren, int numOfLayers, int layerIndex, int[] nodeIndex)
    {
        layer = layerIndex;
        nodeID = nodeIndex[0]++;

        if (numOfLayers > 0 && numOfchildren > 0) {
            children = new ArrayList<Tree> ();
            for (int i = 0; i < numOfchildren; i++) {
                children.add(new Tree(numOfchildren, numOfLayers - 1, layer + 1, nodeIndex));
            }
        }
    }
}

一些值得注意的概念:

  • Tree类包含一个public constructor和一个private constructor。公共构造函数只是一个“干净”的界面。私人做了所有“肮脏”的工作。
  • 私有构造函数的layerIndex参数设置根节点的偏移量。将它设置为0(与公共构造函数一样)是最好的。
  • 私有构造函数的int[] nodeIndex数组参数是一个“解决方法”,用于通过引用发送int参数。数组参数(由public constructor提供)由单个元素数组组成,该数组跟踪到目前为止创建的子项数,以便将nodeID设置为唯一值。

以上是关于Java:如何递归填充树节点的主要内容,如果未能解决你的问题,请参考以下文章

java数据结构二叉树查找结点操作,递归调用求详细讲解

Java - 如何处理叶节点的解析树递归?

java 递归在实例中的几种用途(ps:准确获取树的子节点)

Java菜单树递归

二叉树遍历和延伸

如何使用 JSON 数据递归填充 TreeView