【问题标题】:Generic N-ary Tree (Tree with more than two node per child) Tree Traversal in Java using List for nodes通用 N 元树(每个子节点超过两个节点的树)Java 中的树遍历,使用节点列表
【发布时间】:2012-10-06 19:55:24
【问题描述】:

我一直在尝试实现 Autosys 工作计划的树形表示。 由于每个作业(流程)都可以有一个或多个相关作业,因此我决定使用 n-ary tree 实现,以便我可以映射流程。我也在使用 java 集合。

Q1(已解决):目前的问题是显示功能陷入无限循环。 我尝试查找现有线程,但找不到使用迭代器进行遍历的示例。

Q2:(OPEN)显示函数以Post order方式遍历树。我想以级别顺序方式遍历它,其中节点在级别基础上打印。 根,然后是一级的所有节点,然后是二级的所有节点,依此类推。 DFS 遍历的链接作为另一个问题发布在下面的链接中。 (大家好,我对同一棵树的级别顺序遍历还有另一个问题,我已经在下面给出的链接上发布了这个问题。如果你们能提供帮助,我会很高兴。 Level Order traversal of a generic tree(n-ary tree) in java 让我们为通用树提供更多资源。)

我们能否为刚接触 n 叉树的人提供一个资源丰富的帖子,因为我发现的基本示例很少。

这是我的代码,我从一个具有三个孩子的根节点开始。我计划稍后扩展它。

一个基本问题。不建议在递归中使用迭代器。我尝试在 display() 中单独定义一个迭代器,但它仍然不起作用。

当前树结构:

     root(100)
    /      |       \
  90       50       70
  /        \
20 30   200  300

输出是后序的(不确定这是否意味着 DFS)。

20 30 90 200 300 50 70 100

代码

import java.util.*;
import java.io.*;
import java.util.List;

//The node for the n-ary tree


public class NaryTree 
{
//The display function traverses the tree

void display(NaryTreeNode t)
{
    Iterator<NaryTreeNode> IT = t.nary_list.iterator();
    if(!(IT.hasNext()))   //If the node does not  have any children, enter.
    {
    //    System.out.println("No more childs of this node");
        System.out.print( t.data + " ");
        return;
    }

    while(IT.hasNext()){
        display(IT.next()) ;            //Recursive Call
    }

   System.out.print(t.data + " ");
}

public static void main(String args[]){

    NaryTree t1 = new NaryTree();

    NaryTreeNode root = new NaryTreeNode();

    root.data = 100;

    NaryTreeNode lev_11 = new NaryTreeNode();   lev_11.data=90;
    NaryTreeNode lev_12 = new NaryTreeNode();   lev_12.data=50;
    NaryTreeNode lev_13 = new NaryTreeNode();   lev_13.data=70;
    NaryTreeNode lev_21 = new NaryTreeNode();   lev_21.data=20;
    NaryTreeNode lev_22 = new NaryTreeNode();   lev_22.data=30;
    NaryTreeNode lev_23 = new NaryTreeNode();   lev_23.data=200;
    NaryTreeNode lev_24 = new NaryTreeNode();   lev_24.data=300;

    //Add all the nodes to a list.



    List<NaryTreeNode> temp2 = new ArrayList<NaryTreeNode>();  //Level two first branch
    temp2.add(lev_21);
    temp2.add(lev_22);

    List<NaryTreeNode> temp3 = new ArrayList<NaryTreeNode>();  //level two second branch
    temp3.add(lev_23);
    temp3.add(lev_24);

    List<NaryTreeNode> temp = new ArrayList<NaryTreeNode>();  //level one
    temp.add(lev_11);
    temp.add(lev_12);
    temp.add(lev_13);

    lev_11.nary_list.addAll(temp2);
    lev_12.nary_list.addAll(temp3);
    //Add Temp to root  to form a leaf of the root

    root.nary_list.addAll(temp);
    //Call the display function.
    t1.display(root);

} }

【问题讨论】:

  • 这个怎么编译?您正在尝试将List&lt;NaryTreeNode&gt; 添加到另一个List&lt;NaryTreeNode&gt;。我希望会有一些例外!
  • 纠正自己:这是addAll,因此正确。
  • 您不应更改问题中的代码。会让人们感到困惑。只需接受有效的答案。如果您觉得有必要,请添加另一个代码块进行更改。
  • 显式定义一个迭代器解决了这个问题。
  • 现在下一个问题是显示功能,它不是以DFS或BFS方式显示节点。我是否为此打开一个新问题,或者我可以编辑相同的问题。请指教。

标签: java algorithm generics tree iterator


【解决方案1】:
nary_list.iterator()

每次都创建一个新的迭代器。所以如果一个列表里面有任何东西,这将是一个无限循环;它每次运行时都会创建一个新的迭代器,并且总是在其中包含元素:

while(t.nary_list.iterator().hasNext()){

如果你想直接使用迭代器,你可以这样做:

Iterator<NaryTreeNode> iterator = t.nary_list.iterator();
while (iterator.hasNext()) {

不过,您也可以在 Java 中使用 for each 循环来减少冗长:

for (NaryTreeNode node : t.nary_list) 

编辑

我也会按这个顺序写显示函数,这样你就可以在遍历完迭代器后打印当前节点的值,而不用问!hasNext()

// Display all of my children
for (NaryTreeNode node : t.nary_list) {
    display(node);
}

// Display myself
System.out.println("Value is: " + t.data);

【讨论】:

  • @Sam 另一个提示:您可以直接添加到节点的列表中:root.nary_list.add(lev_11); 您不需要额外的临时列表和addAll
  • @Sam 我知道您是该网站的新手;如果您最终使用我的代码,请投票和/或接受答案(答案左侧有绿色复选标记)。这是我们表达感谢的方式:)。
  • 伙计们,我在帖子中添加了下一个问题。如果您能提供帮助将不胜感激。请告知我是否应该提出一个新问题。我想保留这篇文章作为对基本 n 叉树实现的参考。非常感谢!
  • @CoryKendall 感谢您的编辑,这样效率更高。
  • 大家好,我被困在同一棵树的级别顺序遍历中,我已在下面给出的链接上发布了问题。如果你们能帮忙,那就太好了。 stackoverflow.com/questions/12788641/…
【解决方案2】:

我对 Java 的了解不够多,无法理解该循环中可能发生的情况,但我觉得这很可疑;按照我的阅读方式,您每次通过循环都会创建一个新的迭代器。

我还建议您考虑使用 first-child/next-sibling 选项,而不是在每个节点中放置一个列表。在这个系统中,每个节点(最多)引用两个其他节点:它的第一个子节点(如果它有任何子节点)和它的下一个兄弟节点(除非它是其父节点的最后一个兄弟节点)。然后,您可以通过兄弟列表遍历兄弟列表以枚举子节点,并且您最终不会在每个节点中使用可变长度数组的所有开销。

【讨论】:

  • 第一个孩子和下一个兄弟姐妹是如此优雅。谢谢!
【解决方案3】:

在我看来,您每次通过循环都在创建一个新的迭代器,因此每个都设置为列表的开头。稍后我将尝试添加规范参考。试试:

    Iterator<NsryTreeNode> i = t.nary_list.iterator();
    while(i.hasNext()){
        display(t.nary_list.iterator().next()) ;            //Recursive Call
    }

您可能想查看 http://docs.oracle.com/javase/tutorial/collections/interfaces/list.html 。您可能会发现 ListIterator 具有价值。

【讨论】:

  • ... 并且他正在将List&lt;NaryTreeNode&gt;(即“temp”)添加到List&lt;NaryTreeNode&gt;。我怀疑它是否可以编译!至少它必须在运行时抛出异常?
  • @Steven 我之前试过 (Iterator IT = t.nary_list.iterator();) 很好,但它仍然运行到无限循环。
  • @DonRoby OP给出的确切代码?我不相信这一点,我很想尝试一下我所知道的关于 Java 泛型的所有知识。
  • @Fildor 是运行代码。但我从未将迭代器用于一元树。我只得到子节点的一个值,然后迭代器似乎永远不会增加。
  • 好的,我收回我所说的一切并道歉。还有addAll(Collection)...面团。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
  • 2020-07-25
相关资源
最近更新 更多