C 将递归二叉树遍历转换为迭代二叉树遍历

C 将递归二叉树遍历转换为迭代二叉树遍历,c,recursion,iteration,binary-tree,imperative-programming,C,Recursion,Iteration,Binary Tree,Imperative Programming,我被要求编写迭代版本,但我编写了递归版本,即 void inorderTraverse(BinaryTree root) { if(root==NULL) printf("%d",root->id); else { inorderTraverse(root->left); printf("%d",root->id); inorderTraverse(root->right);

我被要求编写迭代版本,但我编写了递归版本,即

void inorderTraverse(BinaryTree root)
{
    if(root==NULL)
        printf("%d",root->id);
    else
    {
        inorderTraverse(root->left);
        printf("%d",root->id);
        inorderTraverse(root->right);
    }
}
我不是在寻找代码,我想了解如何做到这一点。如果这只是最后一个递归调用,我就会这样做

void inorderTraverse(BinaryTree root)
{
    while(root!=NULL)
    {
        printf("%d",root->id);
        root=root->right;
    }
}
但是当有两个递归调用时,如何转换为迭代程序?

以下是类型定义

struct element{
    struct element* parent;
    int id;
    char* name;
    struct element* left;
    struct element* right;
};
typedef element* BinaryTree;
这就是我的想法,我走对了吗

temp=root;
while(1)
{
    while(temp!=NULL)
    {
     push(s,temp);
     temp=temp->left;
     continue;
    }

    temp=pop(s);
    if(temp==NULL)
    return;
    printf("%d\t",temp->data);
    temp=temp->right;
}

您看到的问题是,您需要“记住”上次迭代的位置。
在执行递归时,程序内部使用“堆栈”来记住返回的位置。
但当进行迭代时,它不会

虽然。。。这给了你一个想法吗?

我想不出一个真正优雅的方法来立即迭代完成这项工作

一种可能是使用一种“标记算法”,从所有节点“未标记”开始,并在处理节点时“标记”节点。标记可以添加到对象模型中,也可以保存在单独的实体中

伪代码:

for (BinaryTree currentNode = leftmostNode(root); currentNode != null; currentNode = nextNode(currentNode)):
  print currentNode;
  currentNode.seen = true;

sub nextNode(BinaryTree node):
  if (!node.left.seen):
    return leftmostNode(node.left)
  else if (!node.seen)
    return node
  else if (!node.right.seen)
    return leftmostNode(node.right)
  else 
    return nextUnseenParent(node)

sub leftmostNode(BinaryTree node):
  while (node.left != null)
    node = node.left
  return node;

sub nextUnseenParent(BinaryTree node):
  while (node.parent.seen)
    node = node.parent
  return node.parent

我想当然地认为,从父节点到左节点的迭代不是问题。问题是要知道从一个节点上升到父节点时要做什么:是应该选择正确的子节点,还是应该再上升一个父节点

以下技巧将帮助您:

在向上移动之前,请记住当前节点。然后往上走。现在您可以比较:您是否在左侧节点:然后选择右侧节点。否则,再上一个父节点


为此,您只需要一个引用/指针。

有一种将递归遍历转换为迭代器的通用方法,它使用一个连接多个迭代器提供者(返回迭代器的lambda表达式)的惰性迭代器。查看我的。

能否显示
BinaryTree
界面?有可能得到一个树节点的父节点吗?可能的重复,我知道这与在堆栈上推东西然后弹出它们有关,但我真的不知道该推什么,何时弹出,以及如何。好的,我可以从推所有节点开始,直到我到达最左边的叶子,然后我开始弹出,现在在弹出第一个后,我把右边的子对象推到stach上,一直推到这个子树最左边的叶子,现在我走到右边的树上,到达这个子树最右边的叶子,但是现在我怎么知道我需要做多少POP才能到达原始树最左边叶子的父级呢?如果可以的话,请帮我多做一些堆叠的事情。@Karan:我不确定我是否完全遵循了你提到的,但你想做的是这样做:(1)按当前节点并尽可能多次地按其左子节点(即,直到没有左节点为止),(2)弹出最后一个节点(这有返回值),(3)对弹出的最后一个节点的右子节点(如果有)重复步骤1。@Karan:我不确定为什么有
if(temp==NULL)
在您的代码中--您从不推送
NULL
,那么为什么要弹出
NULL
?或者这是一种空虚状态的信号?但除此之外,它似乎很好。。。你试过了吗?我也只是想要这样的东西,但这算是一个迭代版本,对吧?而且,我不认为这是一个无序的遍历,事实上,你是从根开始打印的。“迭代步骤”比通常要复杂一些,但它只包含
for
循环,
while
循环,没有递归调用,所以我认为它应该是迭代的。