递归算法
- 先序遍历
// 递归先序遍历
Status PreOrderTraverse(BiTree T)
{
if (T==NULL)
return OK;
printf("%d\n",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
- 中序遍历
// 递归中序遍历
Status InOrderTraverse(BiTree T)
{
if (T==NULL)
return OK;
InOrderTraverse(T->lchild);
printf("%d\n",T->data);
InOrderTraverse(T->rchild);
}
- 后序遍历
// 递归后序遍历
Status LastOrderTraverse(BiTree T)
{
if (T==NULL) // 递归出口,当前结点指向NULL
return OK;
LastOrderTraverse(T->lchild); // 递归遍历左子树
LastOrderTraverse(T->rchild); // 递归遍历右子树
printf("%d\n",T->data); // 遍历完左右子树后,访问当前结点
}
非递归实现(利用栈)
- 先序遍历
// 先序非递归遍历二叉树
Status PreOrderTraverse(BiTree T)
{
BiTree p;
SqStack S;
InitStack(&S);
Push(&S,T); // 根结点入栈
while (!StackEmpty(&S)) // 出栈即访问了结点,栈空即所有结点均已访问,退出循环
{
while (GetTop(&S,&p) && p) // 栈顶的树指针为空,即根结点向左走所有结点都已入栈
{
printf("%d\n",p->data); // 边入栈,边访问(先序遍历)
Push(&S,p->lchild); // 向左走到尽头,把左儿子一路压入栈
}
Pop(&S,&p); // 将空指针出栈
if (!StackEmpty(&S)) // 这个判断用于所有结点均已遍历,不需要再压入右孩子(否则第二句push操作将使得栈永远不为空,无限循环)
{
Pop(&S,&p); // 访问结点
Push(&S,p->rchild); // 让该结点右儿子入栈
}
return OK; // 完成遍历
}
- 中序遍历(算法思想与先序遍历类似,仅仅是访问结点(printf("结点的值"))的时间不同)
Status InOrderTraverse(BiTree T)
{
BiTree p;
SqStack S;
InitStack(&S);Push(&S,T);
while (!StackEmpty(&S))
{
while (GetTop(&S,&p) && p) Push(&S,p->lchild);
Pop(&S,&p);
if (!StackEmpty(&S))
{
Pop(&S,&p);
printf("%d\n",p->data); // 中序遍历在出栈的时候访问结点的值
Push(&S,p->rchild);
}
}
}
- 后序遍历(多了一个判断上一个访问结点的if语句以及退出循环的条件判断)
Status PostOrderTraverse(BiTree T)
{
BiTree p;
BiTree pre=NULL; // 记录上一个访问的结点指针
SqStack S;
InitStack(&S);Push(&S,T);
while (!StackEmpty(&S))
{
while (GetTop(&S,&p) && p)
{
Push(&S,p->lchild);
}
Pop(&S,&p);
if (!StackEmpty(&S))
{
Pop(&S,&p);
if (p->rchild==NULL || pre==p->rchild) // 如果该结点右儿子是上一个访问的结点或者该结点没有右儿子
{
printf("%d\n",p->data); // 访问该节点数据
pre=p; // 将该结点设置为上一个访问的结点
}
else
Push(&S,p); // 右儿子还没被访问,不是访问该结点的时候,压回堆栈
Push(&S,p->rchild);
}
if (pre==T) // 当访问的上一个结点为根结点,表明后序遍历结束,退出循环
break;
}
}