【问题标题】:How can you iterate a k-ary tree?如何迭代 k-ary 树?
【发布时间】:2013-02-20 12:27:24
【问题描述】:

假设您有一个通用的 k-ary 树 like this onethis one

在这里重复后者:

template <typename T>
struct TreeNode
{
  T* DATA ; // data of type T to be stored at this TreeNode

  vector< TreeNode<T>* > children ;

  void insert( T* newData ) ;

  // runs f on this and all children of this
  void preorder( function<void (T*)> f )
  {
    f( this->DATA ) ; // exec f on this
    for( int i = 0 ; i < children.size(); i++ )
      children[i]->preorder( f ) ; // exec f on each child
  }

} ;

template <typename T>
struct Tree
{
  TreeNode<T>* root;

  // TREE LEVEL functions
  void clear() { delete root ; root=0; }

  void insert( T* data ) { if(root)root->insert(data); } 
} ;

现在,通常情况下,您将前序和后序遍历作为TreeNode 的递归成员函数,如上所示。 但是假设你不想传递函数,你想从类外部访问树中的每个节点(即只给定一个Tree 对象) .

你是怎么做到的?

【问题讨论】:

  • 您好我正在尝试使用 Java 实现其输出为相邻矩阵形式的 k 数组树。输入参数是 k = 每个节点的子节点数和 d = 树的深度。给定这个参数,我将生成树的相邻矩阵。我看到了github,无法关注。请您指导我实现这个吗?

标签: algorithm tree iteration


【解决方案1】:

我会通过定义一个PreorderIterator 类来解决这个问题,该类维护关于它在遍历中的位置的状态。它将具有返回当前节点和在遍历中前进一步的方法。

如果树结构在迭代器的生命周期内可能发生变异,您必须小心。也许这棵树可以保持一个修改计数;迭代器可以在开始时捕获计数并在每次访问时检查更改(如果找到则抛出异常)。

【讨论】:

  • 我想过这个问题,但这是否意味着我必须为每个TreeNode 维护一个parent 节点?
  • @bobobobo - 迭代器可以用当前路径的堆栈(以及路径的每一级的当前索引)来实现。这样就不必在树本身中保留父指针。
【解决方案2】:

一种简单的方法是将树加载到列表中,然后在需要时遍历列表。该列表将只是一个指针列表,因此不会那么昂贵。为此,您将使用 the trie traversal algorithm 的修改版本:

void traverse(Node n){
  if(null == n) return;

  for( Node c: n.children){
    visit( c );
    traverse( c );
  }
}

您将使用visit 来实际加载您的列表。所以像

List<Node> getListToIterate(Node n){
   List<Node> result = new ArrayList<Node>();
   traverse(n,resutl);
   return result;
}

void traverse(Node n, List list){
  if(null == n) return;

  for( Node c: n.children){
    list.add( c );
    traverse( c );
  }

}

此外,如果您决定,您可以将此算法封装在 TreeIterator 类中,该类将跟踪您在列表中的位置。

【讨论】:

  • 所以你建议将树展平成一个列表,然后遍历它。如果树很小,那么这个 flattening 操作就不会那么昂贵——如果树不经常改变它甚至更便宜
  • 完全正确。 iterators 的另一个方面可能对您的情况很重要,也可能不重要,那就是不变性。因此,在迭代期间,您不允许底层结构发生变化。如果不变性对您很重要,那么有许多创造性的方法可以使列表非常方便。例如,您可以允许在迭代器函数的 flattening 阶段之后插入底层树。这些当然是您必须创造性地思考的设计优化。基本上,这份清单给了你很大的权力。您如何使用它取决于您的具体需求。
猜你喜欢
  • 2014-01-10
  • 2014-08-26
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多