在C中没有递归和堆栈的遍历树
Posted
技术标签:
【中文标题】在C中没有递归和堆栈的遍历树【英文标题】:Traverse tree without recursion and stack in 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
结构的成员以存储更多信息。
【问题讨论】:
任意顺序,最好是深度优先 我编辑了问题标题(添加了“无堆栈”),以便在有人搜索特定需求时清楚说明 【参考方案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 到结束查看数据。
如果您想避免递归,您需要保留树中每个对象的引用。
【讨论】:
以上是关于在C中没有递归和堆栈的遍历树的主要内容,如果未能解决你的问题,请参考以下文章