【问题标题】:Traverse tree without recursion and stack in C在C中没有递归和堆栈的遍历树
【发布时间】:2011-03-13 23:03:19
【问题描述】:

如何在C(非C++)中有效地遍历树的每个节点而不递归?

假设我有该树的以下节点结构:

struct Node
{
    struct Node* next;   /* sibling node linked list */
    struct Node* parent; /* parent of current node   */
    struct Node* child;  /* first child node         */
}
  • 这不是家庭作业。
  • 我更喜欢深度优先。
  • 我更喜欢不需要额外的数据结构(例如堆栈)。
  • 我更喜欢在速度方面最有效的方式(而不是空间)。
  • 您可以更改或添加Node 结构的成员以存储更多信息。

【问题讨论】:

  • 任意顺序,最好是深度优先
  • 我编辑了问题标题(添加了“无堆栈”),以便在有人搜索特定需求时清楚说明

标签: c data-structures recursion tree traversal


【解决方案1】:

如果您不想存储任何内容,并且可以使用深度优先搜索:

process = TRUE;
while(pNode != null) {
    if(process) {
        //stuff
    }
    if(pNode->child != null && process) {
         pNode = pNode->child;
         process = true;
    } else if(pNode->next != null) {
         pNode = pNode->next;
         process = true;
    } else {
         pNode = pNode->parent;
         process = false;
    }
}

将遍历树; process 是为了防止它在返回时重新命中父节点。

【讨论】:

  • +1 用于识别兄弟节点链表的工作方式,而不是像高分答案那样引入大量无意义的开销......
  • +1。这看起来是对的。因此我删除了我的答案:-)(我使用了额外的节点信息)。解释一下:这是不变量:访问节点时,如果 process 为真,则意味着您尚未遍历该子树。只有在访问完所有子节点后才能返回节点,在这种情况下,进程是错误的,您现在移动到您的兄弟节点。
  • @ShinTakezou:我们不要妄下结论。 布赖恩的答案发布后,该问题被编辑以禁止堆栈。
  • @Moron 我不想贸然下结论。由于堆栈本身,我没有更好地评估这一点。这看起来更好(对我来说!!),因为给出了实现目标的代码,给定了结构。另一个答案很好,但是“通用”;这个似乎更具体(哦,我希望他至少在一开始就给出了结构,并且他后来没有改变它!!)
  • 修改的是我的措辞,而不是我的编码。它最初是“基于布莱恩的回答”,但布莱恩改变了他的,所以它不再相关
【解决方案2】:

通常,您将使用自己的堆栈数据结构,该结构存储节点列表(或队列,如果您想要级别顺序遍历)。

您首先将任何给定的起始节点压入堆栈。然后你进入你的主循环,直到堆栈为空。从堆栈中弹出每个节点后,如果不为空,则推送其下一个节点和子节点。

【讨论】:

  • 这也不会遍历树。
  • 如果我使用链表实现自己的堆栈,会比使用递归更有效吗?
  • @uray:我认为递归函数调用不会成为您程序的瓶颈。但是如果你有一个巨大的巨大的树,那么实现你自己的可能会更有效,因为你可以根据需要自己做一些事情,比如将堆栈的一部分缓存到磁盘。
  • 是否有任何算法不使用任何迭代数据结构(如堆栈或队列),例如通过在该节点结构中修改或添加变量?
  • 阅读 zebediah49 的回答。这里树结构的设计方式,解决起来很简单。
【解决方案3】:

这看起来像是 25 年前我在工程学校做的一个练习。 我认为这被称为树包络算法,因为它绘制了树的包络。

我不敢相信事情就这么简单。我一定在某个地方犯了一个不经意的错误。 不管有什么错误,我相信包围策略是正确的。 如果代码有错误,则将其视为伪代码。

while current node exists{
  go down all the way until a leaf is reached;
  set current node = leaf node;
  visit the node (do whatever needs to be done with the node);

  get the next sibling to the current node;
  if no node next to the current{
    ascend the parentage trail until a higher parent has a next sibling;
  }
  set current node = found sibling node;
}

代码:

void traverse(Node* node){

  while(node!=null){
    while (node->child!=null){
      node = node->child;
    }

    visit(node);

    node = getNextParent(Node* node);
  }
}

/* ascend until reaches a non-null uncle or 
 * grand-uncle or ... grand-grand...uncle
 */
Node* getNextParent(Node* node){

  /* See if a next node exists
   * Otherwise, find a parentage node
   * that has a next node
   */
  while(node->next==null){
    node = node->parent;
    /* parent node is null means
     * tree traversal is completed
     */
    if (node==null)
      break;
  }

  node = node->next;

  return node;
}

【讨论】:

    【解决方案4】:

    您可以使用Pointer Reversal 方法。缺点是需要在节点内部保存一些信息,所以不能在const数据结构上使用。

    【讨论】:

      【解决方案5】:

      您必须将其存储在可迭代列表中。带有索引的基本列表将起作用。然后,您只需从 0 到结束查看数据。

      如果您想避免递归,您需要保留树中每个对象的引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-02
        • 1970-01-01
        • 1970-01-01
        • 2012-02-05
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 2018-07-12
        相关资源
        最近更新 更多