【问题标题】:iterate through recursive objects遍历递归对象
【发布时间】:2015-09-07 10:09:01
【问题描述】:

我正在尝试遍历递归对象,但据我所知,Java 不支持此操作。

例如,给定对象Item

public class Item {

     Long uuid;
     List<Item> children;
}

使用for 循环,我可以遍历children,但由于children 将包含更多children,而children 将包含更多children 等等,因此无法自动确定深度和循环基于那个深度。

有没有办法遍历递归对象?

【问题讨论】:

    标签: java


    【解决方案1】:

    如果树很深,请按照 Eran 的建议使用呼吸优先搜索。如果树很宽,请使用深度优先搜索,如下所示:

    class ItemVisitor { 
        public void accept(Item item) {
            // Do something
            for (Item i : item.getChildren()) {
                this.accept(i);
            }
        }
    }
    

    编辑:

    对于呼吸优先搜索,使用队列并将当前节点的所有子节点附加到它上面。

    public void visitTree(Item head) {
        Queue<Item> queue = new PriorityQueue<Item>();
        while (queue.size() > 0) {
            Item curr = queue.poll();
            // Do something
            for (Item i : curr.getChildren())
                queue.add(i);
        }
    }
    

    【讨论】:

      【解决方案2】:

      如果父子树中没有循环,则可以使用简单的递归函数来确定后代的数量:

      public class Item {
          ...
      
          public int getDescendantCount() {
              int count = 0;
              if (children != null) {
                   count += children.size();
                   for (Item child : children)
                        count += child.getDescendantCount();
              }
              return count;
          }
      }
      

      【讨论】:

        【解决方案3】:

        类似的东西?

        void read(Item item) {
            if (item == null) {
                //do something with the uuid ?
                return;
            } else {
                for (Item i : item.children) {
                    read(i);
                }
            }
        }
        

        【讨论】:

        • 我的 OP 已经引用了 Item,为什么他需要类似 Item 查找的东西?
        【解决方案4】:

        我不知道该函数的确切目标是什么,但您始终可以递归地循环遍历子项。

        例如

         public void loopChildren(List<Item> items) {
             for (Item i : items) {
                 System.out.println(i.uuid);
                 loopChildren(i.children);           
             }       
         }
        

        它只是一直循环直到列表的末尾。如果一个孩子没有孩子 List 应该是空的,所以它会在该迭代中终止。

        希望这会有所帮助。

        【讨论】:

          【解决方案5】:

          如果您可以将深度存储为单独的数据项并通过类设计/封装强制执行它,那么您就很好了。

          您提出的是某种深度不确定的树的节点。您可以实现任何正常的深度优先或广度优先搜索方法;在任何标准数据结构和算法教科书/网络参考中查找它并用 Java 实现。如果您使用堆栈(后进先出或 LIFO 队列),Eran 在我输入时发布的解决方案是标准的深度优先搜索,如果您使用 FIFO 队列,则为广度优先搜索。这些都是不错且干净的方法,但不是最简单的。

          最简单的方法是深度优先搜索的简单递归函数:

          public void recurseIntoChildren(Item item) {
              if(item.children.size() == 0) {
                  // you are now at a leaf node: do something
              }
              for(Item child : item.children) {
                  recurseIntoChildren(child);
              }
          }
          

          这个表单假设你想在叶子节点做一些事情。如果您正在搜索某些内容,您可以让 recurseIntoChildren() 在找到所需内容时返回一个特殊值,这样您就可以跳出所有其余的递归循环(让它返回 null 或其他值以指示循环应该继续)。如果您想采取其他措施,您可以根据自己的需要进行操作。

          这不是最有效的方法(除非编译器将尾递归优化为一个简单的循环)。

          【讨论】:

            猜你喜欢
            • 2020-12-06
            • 1970-01-01
            • 2011-04-18
            • 1970-01-01
            • 2018-01-30
            • 2019-11-01
            • 1970-01-01
            相关资源
            最近更新 更多