(六)1.3_非递归遍历二叉树(先序、中序、后序、层序四种遍历方式)

一.非递归先序遍历

1.思路分析

  a.使用while循环从树根节点开始用指针p遍历二叉树

  b.如果遍历到的节点p不是空树,则访问该节点,并把节点p入栈(入栈是因为回溯访问其右子树需要通过其获得它的右子树),然后p指向p的左子树(向左走)

  c.如果遍历到空树(说明向左走到了尽头),则出栈一个节点,p指向该节点的右子树
(向右走)

  d.就这样一直循环直到栈为空且p指针指向空,则先序遍历二叉树完成


2.代码实现

  //先序遍历二叉树(非递归) 
void PreOrderTraverse(BiTree T,void (*visit)(TElemType *elem))
{
	if(T==NULL)                                //如果空树退出函数 
	     return;
  	BiTree stack[500];                         //用数组创建一个栈 
  	int top=0;                                //栈顶
  	int base=0;  	 	                      //栈底
  	 
	BiTree p=T; 	                          //指向树节点的指针
  	while(p!=NULL||top!=base)                 //p为空同时栈为空时结束循环
   {
	   if(p!=NULL)                            //向左不为空  
	   {                                      //这些操作是向左走到尽头
	   	 visit(&p->data);                     //先序访问节点 
		 stack[top++]=p;                      //节点入栈
		 p=p->lchild;	   	                  //向左子树走
	   }
	  else                                    //节点为空,说明向左走到了尽头,准备出栈
	  {
		 p=stack[--top];                      //节点出栈
		 p=p->rchild;	  	                  //向该节点的右子树走
	  }   
   }  	
}


二.非递归中序遍历

1.思路分析
  中序和先序的非递归遍历算法是类似的,只不过中序是在节点出栈时才对节点进行访问的

  a.使用while循环从树根节点开始用指针p遍历二叉树

  b.如果遍历到的节点p不是空树,则把节点p入栈(入栈是因为要对其回溯访问,而且需要通过其获得它的右子树),然后p指向p的左子树(向左走)

  c.如果遍历到空树(说明向左走到了尽头),则出栈一个节点并访问该节点,然后p指向该节点的右子树(向右走)

  d.就这样一直循环直到栈为空且p指针指向空,则中序遍历二叉树完成


2.代码实现

 //中序遍历二叉树 
void InOrderTraverse3(BiTree T,void (*visit)(TElemType *elem))
{
	  if(T==NULL)                                //如果空树退出函数 
	     return;
	  BiTree stack[500];                         //用数组创建一个栈 
	  int top=0;                                 //栈顶 
	  int base=0;                                //栈底
	  
	  BiTree p=T;                                  //指向树节点的指针 
	  while(p!=NULL||top!=base)                    //p为空同时栈为空时结束循环 
	  {
		  if(p!=NULL)                             //向左不为空  
		  {                                       //这些操作是向左走到尽头 
			 stack[top++]=p;                      //节点入栈 
			 p=p->lchild;		  	              //向左子树走 
		  }
		  else                                    //节点为空,说明向左走到了尽头,准备出栈 
		  {
			  p=stack[--top];                    //节点出栈 
			  visit(&p->data);                   //中序访问节点 
			  p=p->rchild;		  	             //向该节点的右子树走 
		  }	  	
	  }
} 


三.非递归后序遍历

1.思路分析
  类似于先序和后序遍历的非递归算法,非递归后序遍历算法也是需要用到辅助栈,然后进行节点回溯,但非递归后序遍历还需要一个标记指针pre来标记节点的右子树是否被访问过,因为后序遍历是左右子树被访问过才能访问根节点

  a.使用while循环从树根节点开始用指针p遍历二叉树

  b.如果遍历到的节点p不是空树,则把节点p入栈(入栈是因为要对其回溯访问,而且需要通过其获得它的右子树),然后p指向p的左子树(向左走)

  c.如果遍历到空树(说明向左走到了尽头),p获取栈顶元素,不出栈,因为可能其右子树还没有被访问,然后有两种情况
  ①如果栈顶节点p存在右子树且未被访问(p->rchild!=pre),则p指向栈顶节点的右子树(向右走),并且将该右子树入栈,然后p指向右子树节点的左子树(向左走)
  ②如果栈顶节点不存在右子树或者其右子树为已被访问,则出栈一个节点对其进行访问,并把标记指针pre指向节点(标记该节点已被访问),然后p赋为空(为了回溯到节点的根节点).

  d.就这样一直循环直到栈为空且p指针指向空,则后序遍历二叉树完成

2.代码实现

//后序遍历二叉树(非递归) 
void PostOrderTraverse(BiTree T,void (*visit)(TElemType *elem))
{	
    if(T==NULL)      //如果是空树退出函数
	   return;
	BiTree stack[500];   //用数组构建一个栈 
	int top=0;           //栈顶 
	int base=0;          //栈底 
	
	BiTree p=T;                   //指向树节点的指针
	BiTree pre=NULL;			  //用于标记前一访问位置的指针 
	while(p!=NULL||top!=base)    	//当p为空且栈为空时退出循环 
	{
		if(p!=NULL)                 //树非空 
		{                           //这些操作是向左走到尽头
		 	stack[top++]=p;         //左子树入栈 
		 	p=p->lchild;		 	//向左走 
		}
		else                        //节点为空,说明向左走到了尽头,准备出栈
		{
			p=stack[top-1];                             //先读取栈顶元素,但是不出栈,因为可能其右子树还没有被访问 
			if(p->rchild!=NULL&&p->rchild!=pre)         //如果有右子树,且右子树没有被访问 
			{
				p=p->rchild;                            //向右走 
				stack[top++]=p;                         //右子树入栈 
				p=p->lchild;				            //遍历右子树的左子树 
			}
			else                                       //没有右子树或者右子树已经被访问 
			{			
		        p=stack[--top];                           //根节点出栈 
		        visit(&p->data);                          //后续访问根节点 
			    pre=p;                                    //标记节点已被访问 
			    p=NULL;                                   //用于回到根节点 
			}				
		}		
	}
}


四.层序遍历

1.思路分析
  a.层序遍历需要一个辅助队列,先把树根节点T入队

  b.然后进行while循环
  第一步:进行出队,访问出队节点p
  第二步:如果出队节点p的左子树存在,则使其左子树入队
  第三步:如果出队节点p的右子树存在,则使其右子树入队

  c.就这样循环直到队列为空,则层序遍历二叉树完成

2.代码实现

//层序遍历二叉树(非递归) 
void LevelOrderTraverse(BiTree T,void (*visit)(TElemType *elem))
{     
	  if(T==NULL)                        //如果空树退出函数 
	    return;
	  BiTree queue[500];               //用数组创建一个队列 
	  int front=0;                     //队头 
	  int rear=0;                      //队尾 
	  queue[rear++]=T;                 //根节点入队	   
	  BiTree p;                       //遍历树节点的指针   
	  	                      
	    while(front!=rear)
	   {   
	      p=queue[front++];                              //出队
		  visit(&p->data);                               //遍历根节点
		  if(p->lchild!=NULL)			                 //左孩子非空入队 
			queue[rear++]=p->lchild;		    
		  if(p->rchild!=NULL)                            //右孩子非空入队
			queue[rear++]=p->rchild;	  	
	   }	  	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值