问题:
非常经典的问题,将一个二叉树遍历,前序,中序,后序遍历由递归转换成非递归。
分析:
递归转换成非递归,一般解法是自己使用栈去模拟递归过程,首先我们来看下后序遍历递归解法:
void postOrderTraverse(pNode root)
{
if(root == NULL)
return ;
postOrderTraverse(p->left);
postOrderTraverse(p->right);
visit(p);
return ;
}
从上面递归过程可以看出来,首先是从左子树一直递归下去,知道为空,然后从栈中返回一个节点,再从这个节点的右节点进行遍历,最后才访问根节点,这里后序遍历的非递归算法,需要一个小trick,p自身需要做个标记,标记当前的右节点是否已经遍历,如果没有遍历,执行右节点任务,如果已经执行,可以访问自己。
代码如下:
void PostTraverse(BINARYTREE p)
{
while (p != NULL || !Stack.IsEmpty()) //存在工作(手头或待完成)
{
while (p != NULL) //处理手头工作,直到无现成手头工作
{
Stack.Push(p, RCHILD_AND_ITSELF);
p = p->LChild;
}
if (!Stack.IsEmpty()) //是否存在待完成工作
{
Stack.Pop(p, Tag);
if (Tag == RCHILD_AND_ITSELF) //情况一: RChild & Itself
{
Stack.Push(p, ONLY_ITSELF)
//保存待完成工作
p = p->RChild; //新的手头工作
}
else //tag == ONLY_ITSELF, 情况二: Only Itself
{
visit(p);
p = NULL; //已无现成的手头工作
}
}
}
}
总结:
从上面代码可以看出,递归转换成非递归,我们需要使用栈来模拟。
用一个指针变量保存当前执行的任务,p
用一个栈保存将要执行的任务,Stack
如果p为NULL了,说明当前手头没有任务,我们需要从Stack中选择一个任务,如果Stack为空,说明当前所有任务都已经完成
理解了手头任务和待完成任务,自行用栈模拟就比较好理解、实现了。