二叉树非递归遍历

二叉树非递归遍历:

#include"btree.cpp"文件链接:https://blog.csdn.net/qq_16261421/article/details/105920539

总体代码如下:

#include "btree.cpp"

//先序非递归遍历算法
void PreOrder1(BTNode *b)	
{
	BTNode *St[MaxSize],*p;
	int top=-1;
	if (b!=NULL) { 
		//根结点进栈  
		top++;						
		St[top]=b;
		//栈不为空时循环
		while (top>-1){
			p=St[top];
			//退栈并访问该结点			
			top--;
			printf("%c ",p->data);
			if (p->rchild!=NULL){
				top++;
               	St[top]=p->rchild;
			}
			if (p->lchild!=NULL){
				top++;
               	St[top]=p->lchild;
			}
		}
		printf("\n");
	}
}

//中序非递归遍历算法
void InOrder1(BTNode *b)	
{
	BTNode *St[MaxSize],*p;
	int top=-1;
	if (b!=NULL){
		p=b;
		//处理*b结点的左子树
		while (top>-1 || p!=NULL){
			//扫描*p的所有左结点并进栈
			while (p!=NULL){
				top++;
				St[top]=p;
				p=p->lchild;
			}
			//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
			if (top>-1){	
				p=St[top];				//出栈*p结点
				top--;
				printf("%c ",p->data);	
				p=p->rchild;			//扫描*p的右孩子结点
			}
		}
		printf("\n");
	}
}

//后序非递归遍历算法
void PostOrder1(BTNode *b)	
{
	BTNode *St[MaxSize];
	BTNode *p;
	int flag,top=-1;				//栈指针置初值
	if (b!=NULL){
		do{
			while (b!=NULL)		{
				//将*b的所有左结点进栈
				top++;
				St[top]=b;
				b=b->lchild;
			}
			//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
			p=NULL;					//p指向栈顶结点的前一个已访问的结点
			flag=1;					//设置b的访问标记为已访问过
			while (top!=-1 && flag){
				b=St[top];			//取出当前的栈顶元素
				if (b->rchild==p)	{	
					printf("%c ",b->data);	//访问*b结点
					top--;
					p=b;			//p指向刚访问过的结点
				}
				else{	
					b=b->rchild;	//b指向右孩子结点
					flag=0;			//设置未被访问的标记
				}
			}
		} while (top!=-1);
		printf("\n");
	} 
}

int main()
{
	BTNode *b;
	CreateBTNode(b,"A(B(D(,G)),C(E,F))");
	printf("b:");
	DispBTNode(b);
	printf("\n");
	printf("先序遍历序列:");
	PreOrder1(b);
	printf("中序遍历序列:");
	InOrder1(b);
	printf("后序遍历序列:");
	PostOrder1(b);
	return 0;
}

 

先序遍历非递归算法:

算法思想:

      用栈来消除递归,先将根节点进栈,在栈不空时候循环:出栈p,访问*p节点,若其右孩子节点不空,将右孩子节点进入堆栈,若其左孩子节点不空,将其左孩子节点进入堆栈。算法如下:

void PreOrder1(BTNode *b)	
{
	BTNode *St[MaxSize],*p;
	int top=-1;
	if (b!=NULL) { 
		//根结点进栈  
		top++;						
		St[top]=b;
		//栈不为空时循环
		while (top>-1){
			p=St[top];
			//退栈并访问该结点			
			top--;
			printf("%c ",p->data);
			if (p->rchild!=NULL){
				top++;
               	St[top]=p->rchild;
			}
			if (p->lchild!=NULL){
				top++;
               	St[top]=p->lchild;
			}
		}
		printf("\n");
	}
}

 

中序遍历非递归算法:

算法思想:

      由中序遍历的过程可知,中序序列的开始节点是一颗二叉树的最左下节点。因此,我们的基本思路是,先找到二叉树的开始节点,并且访问它,再处理右子树。

     用指针指向当前要处理的节点,先扫描(并非访问)根节点的所有左节点,并且将它们一一进栈,当无左节点时,表示栈顶节点无左子树,然后出栈这个节点,并访问它,将p指向刚出栈节点的右孩子,对右子树进行同样的处理。 

     需要特别注意的是,当节点*p的所有左节点进栈后,这时的栈顶节点要么没有左子树,要么左子树已经被访问过,就可以访问这个栈顶节点,如此重复操作,直到栈空为止。算法如下:

//中序非递归遍历算法
void InOrder1(BTNode *b)	
{
	BTNode *St[MaxSize],*p;
	int top=-1;
	if (b!=NULL){
		p=b;
		//处理*b结点的左子树
		while (top>-1 || p!=NULL){
			//扫描*p的所有左结点并进栈
			while (p!=NULL){
				top++;
				St[top]=p;
				p=p->lchild;
			}
			//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
			if (top>-1){	
				p=St[top];				//出栈*p结点
				top--;
				printf("%c ",p->data);	
				p=p->rchild;			//扫描*p的右孩子结点
			}
		}
		printf("\n");
	}
}

 

后续遍历非递归算法:

算法思路:

    后续遍历中第一个访问的节点是二叉树的最左下节点。由于首先访问节点的左右子树,然后才访问节点本身,所以对于任意节点,必须直到其左右子树是否被访问过。

    使用栈来保存需要返回的节点的指针,先扫描根节点的所有左孩子节点,并且一一进栈,出栈一个节点*p作为当前节点,然后扫描该节点的右子树,当一个节点的左右孩子节点均被访问后再访问该节点,如此重复,直到栈空为止。

    Q:如何判断一个节点*b的右子树已经访问过?

    A:如果右孩子节点已经访问过,则其右子树就已经访问过。 

    用p指针保存刚访问过得节点,若b->rchild==p成立,则b的左右子树均已访问,现在应该访问*b。所以栈中保存的是当前节点*b的所有祖先节点。这些祖先节点均未被访问过。

算法如下:

//后序非递归遍历算法
void PostOrder1(BTNode *b)	
{
	BTNode *St[MaxSize];
	BTNode *p;
	int flag,top=-1;				//栈指针置初值
	if (b!=NULL){
		do{
			while (b!=NULL){
				//将*b的所有左结点进栈
				top++;
				St[top]=b;
				b=b->lchild;
			}
			//执行到此处时,栈顶元素没有左孩子或左子树均已访问过
			p=NULL;					//p指向栈顶结点的前一个已访问的结点
			flag=1;					//设置b的访问标记为已访问过
			while (top!=-1 && flag){
				b=St[top];			//取出当前的栈顶元素
				if (b->rchild==p)	{	
					printf("%c ",b->data);	//访问*b结点
					top--;
					p=b;			//p指向刚访问过的结点
				}
				else{	
					b=b->rchild;	//b指向右孩子结点
					flag=0;			//设置未被访问的标记
				}
			}
		} while (top!=-1);
		printf("\n");
	} 
}

后序非递归遍历算法特点:当访问某个节点时,堆栈中保存的正好是该节点的所有祖先节点,从栈顶到栈底正好是该节点的双亲  节点到根节点路径上的节点序列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值