我一直在尝试在工作中实现Autosys作业计划的树形表示。 由于每个作业(进程)可以有一个或多个依赖作业,我决定使用n-ary树实现,以便我可以映射流。我使用的是java集合。
Q1(已解决):现在的问题是显示功能在无限循环中挂起。 我试图寻找现有的线程但是没有遇到使用迭代器的遍历的例子。
Q2:(OPEN)显示功能以Post Order方式遍历树。我想以级别顺序的方式遍历它,其中节点在级别基础上打印。 Root,然后是第1级上的所有节点,然后是第2级上的所有节点,依此类推。 DFS遍历的链接在下面的链接中作为另一个问题发布。 (大家好,我对同一棵树的关卡顺序遍历有另外一个问题,我已经在下面给出的链接上发布了这个问题。如果你们能提供帮助,那将是一个问题。 Level Order traversal of a generic tree(n-ary tree) in java 让我们为通用树提供更多资源。)
我们能否为那些有n-ary树的新人提供一份资源丰富的帖子,因为我发现很少有基本的例子。
这是我的代码,其中我已经开始使用具有三个子节点的根节点。我打算稍后再扩展它。
一个基本问题。是不是建议在递归中使用迭代器。我尝试在display()中单独定义一个Iterator,但它仍然无效。
当前树结构:
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);
} }
答案 0 :(得分:3)
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);
答案 1 :(得分:2)
在我看来,每次循环都会创建一个新的迭代器,因此每个都设置为列表的开头。我稍后会尝试添加规范参考。尝试:
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具有值。
答案 2 :(得分:2)
我不知道Java能够理解该循环中可能发生的事情,但它看起来很可疑;我读到的方式是,每次循环都会创建一个新的迭代器。
我还建议您考虑使用first-child / next-sibling而不是在每个节点中放置列表。在这个系统中,每个节点引用(最多)两个其他节点:它的第一个子节点(如果它有任何子节点)和它的下一个兄弟节点(除非它是它的父节点的最后一个兄弟节点)。然后,您可以通过兄弟列表遍历兄弟列表以枚举子节点,并且您不会在每个节点中获得可变长度数组的所有开销。