后序遍历的非递归算法(C 详细)

后序遍历二叉树是先访问左子树,再访问右子树,最后访问根结点。

算法思想:

  1. 先沿根结点,依次入栈,直到左孩子为空
  2. 读取栈顶元素;如果其右孩子不空且未被访问过,将右子树转执行 1;
  3. 否则,栈顶元素出栈并访问。
void PostOrder(BiTree T){
	InitStack(S);
	p=T;
	r=NULL;
	while(p!=NULL||!IsEmpty(s)){
		if(p!=NULL){				//走到最左边 
			push(S,p);
			p=p->lchild;
		}
		else{				//向右
			GetTop(S,p);	//读栈顶节点(非出栈) 
			if(p->rchild&&p->rchild!=r){	//若右子树存在,且未被访问过 
				p=p->rchild;	//转向右 	
			}
			else{				//否则弹出结点并访问 
				pop(S,p);
				visit(p->data); //访问该结点
				r=p;			//记录最近访问的结点 
				p=NULL;			//结点访问完后,重置p指针
			}
		}
	}

后序序列D E B C A
后序序列D E B C A

以此为例,按照代码推演一遍:

按照第一个if语句中的 p!=NULL 且 p=p->lchild;

依次将 ABD 入栈
在这里插入图片描述
此时,p指针是指向D结点的左子树,所以为空;
跳出第一个if(p!=NULL)判断

然后转到 GetTop(S,p); 语句
将p指针指向栈顶的D结点;

然而 if(p->rchild) 判断中,D也无右结点。

这时转到pop语句;将D结点作为后序遍历的第1个结点,且r指针指向D

因为p置为NULL了,所以跳转到GetTop(S,p);p指向了栈顶B结点.

可知p=p->rchild,把p指针指向了B的右结点E;(此时r指向D,p指向E)
因为p!=NULL,会push(S,p); E结点入栈
此时堆栈情况: 在这里插入图片描述

因为E无左子树,同时E也无右子树,

if(p->rchild&&p->rchild!=r)

所以出栈访问,将E结点作为后序遍历的第2个结点;
r指向E结点,p置空

	pop(S,p);			
				visit(p->data); 
				r=p;			
				p=NULL;		

之后因为r指向E,p指向B (因为GetTop(S,p); 会把p指向B)

p->rchild!=r 会阻止再次访问 访问过的结点,即E结点,所以将B出栈,将E结点作为后序遍历的第3个结点;
r指向B,p置空

接着对栈顶元素A进行判断,C结点相应入栈出栈,同理,r指针指向C,防止二次访问右子树C;
最后将A出栈,栈空,break while循环。

r指针的作用:

可以看出p指针指向栈顶元素时,如果元素存在右子树,且r指针保留了访问过的右子树,就会阻止访问,直接使栈顶元素出栈
这也是后序遍历不同于先序、中序,所要特别处理的地方。

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robinτ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值