递归算法和非递归算法的转换:
可以借助栈,将二叉树的递归算法转换为非递归算法,下面以中序遍历为例给出中序遍历的非递归算法。先扫描(并非访问)根结点的所有左结点并将他们一一进栈。然后出战一个结点 *p(显然结点*p没有左孩子结点或者左孩子结点均已访问过),则访问它。然后扫描该结点的有孩子结点,将其进栈在扫描该右孩子结点的所哟左结点并一一进栈,如此继续,知道栈空为止。
/*中序遍历非递归算法*/
void InOrder2(BiTree tree, void(*visit)())
{
Sqstack S;
S.top = -1;
BiTree p = tree;
while (p||!isempty(S)) //栈不空或P不空时循环
{
if (p)
{
push(&S, p); //根指针进栈,遍历左子树;
p = p->lchild; //每遇非空二叉树先向左走;
}
else
{
p=pop(&S,p); //根指针退栈,访问根结点,遍历右子树;
visit(p->data); //退栈,访问根节点
p = p->rchild; //再向右子树走
}
}
}
在说一下比较麻烦的后序非递归二叉树遍历算法:
算法的思想:
因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根结点。当用栈来存储结点,必须分清返回的根结点时,是从左子树返回的,还是从右子树返回的。所以,使用辅助指针r,其指向最近访问过的结点。也可以在结点中增加一个标志域,记录是否已经访问过;
/*后序遍历非递归算法*/
void PostOrder2(BiTree tree, void(*visit)())
{
Sqstack S;
S.top = -1;
BiTree p = tree;
BiTree q = NULL;
BiTree r = NULL;
while (p || !isempty(S)) //栈不空或P不空时循环
{
if (p)
{ //走到最左边
push(&S, p);
p = p->lchild;
}
else
{
p= gettop(&S,q); //取栈顶点
if ((p->rchild)&&p->rchild!=r) //如果右子树存在,且未被访问过
{
p = p->rchild; //转向右
push(&S, p); //压入栈
p = p->lchild; //在走到最左
}
else
{
q=pop(&S, q); //将结点弹出
visit(q->data); // 访问该节点
r = q; //记录最近访问过的的结点
p = NULL; //结点访问完后,重置p指针
}
}
}
}
附加上先序遍历非递归算法:理解同中序类似;
/*先序遍历非递归算法*/
void PreOrder2(BiTree tree, void(*visit)())
{
Sqstack S;
S.top = -1;
BiTree p = tree;
while (p || !isempty(S)) //栈不空或P不空时循环
{
if (p)
{
push(&S, p);
visit(p->data);
p = p->lchild;
}
else
{
p = pop(&S, p);
p = p->rchild;
}
}
}