面试经典(13)--二叉树非递归遍历

本文详细介绍了二叉树的三种遍历方法:前序遍历、中序遍历和后序遍历,并提供了每种遍历方法的非递归实现代码。通过深入分析遍历算法,帮助读者理解其工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.中序遍历

中序遍历的思路分析:第一次遍历到节点,要一直遍历到此节点左子树上最左侧的节点,此过程将遍历到的节点按先后顺序依次入栈。到大最左侧时,将栈顶元素出栈并输出,并将此节点的右子树入栈,然后再从头开始,是不是明显看到递归的影子了!

代码如下:

stack<Node*> s;
void InOrder(Node *pRoot)
{
	if(pRoot==NULL)
	{
		return;
	}
	Node *p=pRoot;
	s.push(p);
	while(!s.empty())
	{
		p=s.top();
		while(p)
		{
			p=p->m_pLeft;
			s.push(p);	
		}
		s.pop();
		if(!s.empty())
		{
			Node *p=s.top();
			s.pop();
		    cout<<p->m_chValue<<" ";
		    s.push(p->m_pRight);
		}
	}
}

注意:上面代码19行处if(!s.empty)这条判断语句是不能省略的。因为当栈为空的时候,输出节点会出错。具体分析为什么要加这个判定语句,从代码看,while(不为空)进入循环,在进入if()判定之前有一个pop动作,所以这有可能使栈为空,是什么情况呢?就是在访问中序遍历的最后一个节点时(”最右“节点)。中序遍历访问的最后一个节点是“最右"节点(即它的右子树肯定为空,如果它的右子树非空,那么遍历会进入右子树,那么就不是最后访问的节点)。这个”最右"元素Node *p=top(),s.pop()出栈并输出。然后s.push(p->m_Right)(p->m_Right为空),所以NULL入栈。接下来进入while循环,栈中只有一个NULL,所以弹出NULL之后栈为空,如果不做判定直接输出会报错。分析这个过程的最简单的例子是分析一棵只有一个节点的树(这个节点就是”最右"节点)来体会上述分析过程。

2.后续遍历

后续遍历的非递归方式是最复杂的。要保证根节点在左右子树访问之后访问,对于任何一个节点p,先将其入栈,如果p没有左右子树,直接出栈访问,或者有左/右子树,但是已经访问过了,同样可以出栈并访问。如果不是这俩种情况,我们先将右子树入栈,再将左子树入栈,这样保证了先访问左子树,在访问右子树,最后访问根节点。

这里的关键是怎么确定当前节点cur的左右子树是否应经访问,可以使用pre指向当前节点cur前一个访问的节点,如果pre=cur->left(没有右子树)或者pre=cur->right(有右子树),则表明cur的左右子树已经访问。

代码:

void PostOrder(Node *pRoot)
{
	Node *cur,*pre=NULL;
	if(pRoot==NULL)
	{
		return;
	}
	s.push(pRoot);
	while(!s.empty())
	{
		cur=s.top();
		//当前节点没有左右子树或者左右子树应经访问过
		if((cur->m_pLeft==NULL && cur->m_pRight==NULL)||(pre!=NULL&&(pre==cur->m_pLeft||pre==cur->m_pRight)))
		{
			s.pop();
			cout<<cur->m_chValue<<" ";
			pre=cur;
		}
		else
		{
			if(cur->m_pRight)
				s.push(cur->m_pRight);
			if(cur->m_pLeft)
				s.push(cur->m_pLeft);
		}
	}
}

3.前序遍历非递归

思路分析:

如果看懂了上面的后续遍历,相信会很快写出前序遍历。前序遍历会先遍历根节点,然后遍历左、右子树。我们将栈顶元素出栈并输出,如果根节点有左右子树,然后将右子树先入栈,再将左子树入栈。

代码如下:

void PreOrder(Node *pRoot)
{
	if(pRoot==NULL)
	{
		return;
	}
	s.push(pRoot);
	while(!s.empty())
	{
		Node *p=s.top();
		cout<<p->m_chValue<<" ";
		s.pop();
		if(p->m_pRight)
			s.push(p->m_pRight);
		if(p->m_pLeft)
			s.push(p->m_pLeft);
	}
}



参考:http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值