用非递归的方式遍历二叉树

1、前序遍历的非递归实现

 

 

根据先序遍历的顺序,先访问根节点,再访问左子树,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历,非递归的实现思路如下:

对于任一节点P

1)输出节点P,然后将其入栈,再看P的左孩子是否为空;

2)若P的左孩子不为空,则置P的左孩子为当前节点,重复1)的操作;

3)若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;

4)若不为空,则循环至1)操作;

5)如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复4)和5)操作;

6)直到当前节点PNULL并且栈空,遍历结束。

 

2、中序遍历的非递归实现

根据中序遍历的顺序,先访问左子树,再访问根节点,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历,非递归的实现思路如下:

对于任一节点P

1)若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;

2)若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;

3)若不为空,则重复1)和2)的操作;

4)若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复3)和4)的操作;

5)直到当前节点PNULL并且栈为空,则遍历结束。

 

3、后序遍历的非递归实现

根据后序遍历的顺序,先访问左子树,再访问右子树,后访问根节点,而对于每个子树来说,又按照同样的访问顺序进行遍历。后序遍历的非递归的实现相对来说要难一些,要保证根节点在左子树和右子树被访问后才能访问,思路如下:

对于任一节点P

1)先将节点P入栈;

2)若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;

3)若不满足2)中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作2);

4)直到栈空,遍历结束。




//非递归前序遍历1

void pre_order (BTreeNode *node)
{
if (node == NULL)
{
errno = ERROR;
return;
}
LinkStack *Stack = Create_Stack ();
BTreeNode *tmp = node;   //指向当前节点
while (tmp)
{
printf("%4c",tmp->data);
Push (Stack,tmp);
if (tmp->lchild)
{
tmp = tmp->lchild;
continue;
}
while(StackEmpty(Stack) != TRUE)
{
Pop (Stack,&tmp);
if(tmp = tmp->rchild)
{
break;
}
}
}
}
}
//非递归前序遍历2
void pre2_order (BTreeNode *node)
{
if (node == NULL)
{
errno = ERROR;
return;
}
LinkStack *Stack = Create_Stack ();
BTreeNode *tmp = node;   //指向当前节点
while (tmp)
{
printf("%4c",tmp->data);
Push (Stack,tmp);
if (tmp->lchild)
{
tmp = tmp->lchild;
continue;
}
while(Pop (Stack,&tmp) && (tmp = tmp->rchild) == NULL);
}
}


//非递归中序遍历1
void mid_order (BTreeNode *node)
{
if (node == NULL)
{
errno = ERROR;
return;
}
LinkStack *Stack = Create_Stack ();
BTreeNode *tmp = node;   //指向当前节点
while (tmp)
{
Push (Stack,tmp);
if (tmp->lchild)
{
tmp = tmp->lchild;
continue;
}
tmp = tmp->rchild;
while(StackEmpty(Stack) != TRUE && tmp == NULL)
{
Pop (Stack,&tmp);
printf("%4c",tmp->data);
tmp = tmp->rchild;
}
}
}
//非递归中序遍历2
void mid2_order (BTreeNode *node)
{
if (node == NULL)
{
errno = ERROR;
return;
}
LinkStack *Stack = Create_Stack ();
BTreeNode *tmp = node;   //指向当前节点
while (tmp)
{
Push (Stack,tmp);
if (tmp->lchild)
{
tmp = tmp->lchild;
continue;
}
tmp = tmp->rchild;
while(tmp == NULL && Pop (Stack,&tmp))
{
printf("%4c",tmp->data);
tmp = tmp->rchild;
}
}
}



//非递归后序遍历
void last2_order (BTreeNode *node)
{
if (node == NULL)
{
errno = ERROR;
return;
}
LinkStack *Stack = Create_Stack ();
BTreeNode *tmp = node;   //指向当前节点
BTreeNode *pre = NULL;  //指向被输出的节点
Push (Stack,tmp);
while (StackEmpty (Stack) != TRUE)
{
GetTop (Stack,&tmp);
//若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出
if(tmp->lchild == NULL && tmp->rchild == NULL 
|| pre != NULL &&(tmp->lchild == pre || tmp->rchild == pre))
{
Pop (Stack,&tmp);
printf("%4c",tmp->data);
pre = tmp;//指向被输出的节点
continue;
}
if(tmp->rchild)
{
Push (Stack,tmp->rchild);
}
if(tmp->lchild)
{
Push (Stack,tmp->lchild);
}
}

}


//层次遍历(用栈代替队列)
void level_order(BTreeNode *node)
{
if (node == NULL)
return;

LinkStack *s1 = Create_Stack ();
LinkStack *s2 = Create_Stack ();
Push (s1,node);  // 根节点进队

while (StackEmpty (s1) != TRUE)
{
// 队头元素出队
BTreeNode* tmp = NULL;
if (StackEmpty (s2) != TRUE)      //栈2不空,就出栈2
{
Pop (s2,&tmp);
}
else
{
Pop (s1,&tmp);
while(StackEmpty (s1) != TRUE)  //把栈1的元素导入到栈2,最后一个不用,直接输出
{
Push (s2,tmp);
Pop (s1,&tmp);
}
}
printf ("%4c", tmp->data);
if (tmp->lchild != NULL)
Push (s1,tmp->lchild);  // 左节点入队

if (tmp->rchild != NULL)
Push (s1,tmp->rchild);  // 右节点入队
}
free(s1);
free(s2);
}
//层次遍历(队列实现)(老师的)
void level_order(BTreeNode *root)
{
if (root == NULL)
return;

LinkQueue * queue = CreateQueue();
EnQueue (queue, root);  // 根节点进队

while (!QueueEmpty(queue))
{
// 队头元素出队
BTreeNode* p = NULL;
DeQueue(queue, &p);
printf ("%4c", p->data);
if (p->lchild != NULL)
EnQueue(queue, p->lchild);  // 左节点入队

if (p->rchild != NULL)
EnQueue(queue, p->rchild);  // 右节点入队
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值