非递归方式遍历二叉树的原理

一、递归遍历代码

// 先序遍历
void PreOrder(BiTNode *T){
	if (T!=NULL){
		visit(T);  // 最简单的visit就是printf(T->data)
		PreOrder(T->lChild);
		PreOrder(T->rChild);
	}
}

// 中序遍历
void InOrder(BiTNode *T){
	if (T!=NULL){
		InOrder(T->lchild);
		visit(T);
		InOrder(T->rchild);
	}
}

// 后序遍历
void PostOrder(BiTNode *T){
	if (T!=NULL){
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		visit(T);
	}
}

二、三种遍历过程示意图以及非递归遍历相关原理

以表达式a*b-c为例构建二叉树,则对该二叉树进行前序遍历就是前缀表达式,中序遍历就是中缀表达式,后序遍历就是后缀表达式。三种遍历过程示意图如下:
请添加图片描述
虚线表示递归执行过程(箭头向下表示前往更深一层的递归调用,箭头向上表示从递归调用推出返回);虚线旁的三角形、圆形、方形内的字符分别表示在先序、中序、后序遍历二叉树过程中访问节点时输出的信息。

从上图可知(也可从去掉visit的代码得知),从递归执行过程的角度来看先序、中序、后序遍历,是完全相同的。仿照递归算法执行过程中递归工作栈的状态变化状况可直接写出相应的非递归算法。

对于中序遍历递归算法,当栈顶记录中的指针非空时,应遍历左子树,即指向左子树根的指针进栈;若栈顶记录中的指针为空,则应退至上一层。若是从左子树返回,则应访问当前层即栈顶记录中指针所指的根节点;若是从右子树返回,则表明当前层的遍历结束,应继续退栈。

从另一角度看,这意味着遍历右子树时不再需要保存当前层的根指针。

以此可以更加深刻理解那句“只有后序遍历可以找到一个节点的祖先”
因为前序、中序遍历,遍历到右子树节点时,右子树的左兄弟和父节点都遍历完成,且不会在后面的遍历过程中被需要,因此可直接退栈。所以这两种遍历方式并不能找不到一个右子树节点的所有祖先。

而对于后序遍历,根据左右根的顺序,若当前节点是一个左子树的节点,那么:1)其右兄弟还未进栈;2)其父节点进栈了但没有被访问而弹出。因此栈中保存的就是该节点到其祖先节点的路径;
若当前节点是一个右子树的节点,那么:1)其左子树在返回根节点之前就被访问并弹出了;2)其父节点进栈了但没有被访问而弹出。

因此可知后序遍历可以找到一个节点的祖先(栈中有且只有所有祖先所串成的整个路径)

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值