二叉树的非递归遍历

非递归 二叉树遍历

Posted by lvyonghao on February 2, 2021

二叉树的非递归遍历

在常规的二叉树的遍历的三种方式中,先序,中序,后序遍历,均采用了递归的方式。如果采用递归的方式是如何操作的?我们都知道递归调用,其实离不开栈的使用,我们如果能手动模拟栈,就能使用非递归的方式进行遍历,接下来将分别写一下非递归遍历的伪代码。


先序遍历

void PreOrder(BiTree T){
	InintStack(S);
	BiTree p = T;	//初始化栈s,p是遍历指针
	whlie(p || !IsEmpty(S)){	//栈不空或p不空时循环
		if(p){				   //一路向左
			visit(p);
			Push(S,p);			//访问当前节点,并入栈
			p = p->lchild		//左孩子不空,一直往左走
		}
		else{					//出栈,并转向栈顶节点的右子树
			Pop(S,p);			//栈顶元素出栈
			p = p-> rchild		//向右子树走,p赋值为当前节点的右孩子
		}
	}
}

中序遍历

中序遍历和先序遍历非常类似,区别在于访问顺序不一样

void InOrder(BiTree T){
	InintStack(S);
	BiTree p = T;	//初始化栈s,p是遍历指针
	whlie(p || !IsEmpty(S)){	//栈不空或p不空时循环
		if(p){				   //一路向左
			Push(S,p);			//并入栈
			p = p->lchild		//左孩子不空,一直往左走
		}
		else{					//出栈,并转向栈顶节点的右子树
			Pop(S,p);			//栈顶元素出栈
			visit(p);			//访问当前节点
			p = p-> rchild		//向右子树走,p赋值为当前节点的右孩子
		}
    }
}

后序遍历

后序遍历和前两种还是有区别的,后序遍历需要保证左右孩子都被访问后,并且左孩子要在右孩子之前访问才能访问根节点。

后序遍历的算法思路分析:从根节点开始入栈,然后沿着其左子树一直往下搜索,知道搜索到没有左孩子节点,此时还不能进行出栈访问,因为如果有其右子树,还需要按相同的规则对右子树进行处理,直到上述操作不能进行为止,若栈顶元素想出栈,要么右子树为空,要么右子树被访问完(此时左子树已经被访问完),这样就保证了正确的访问顺序。

void PostOrder(BiTree T){
	InitStack(S);
	BiTree p = T;
	r = NULL;
	while(p || IsEmpty(S)){
		if(p){					//走到最左面
			Push(S,p);
			p = p->lchild;
		}else{					//向右
			GetTop(S,p);		//找到栈顶元素
			if(p->rchlid && p->rchild != r){		//若右子树存在且未访问
				p = p->rchild;			//转向右
				Push(S,p);				//压入栈
				p = p->lchild			//再转向左
			}else{								  //否则,弹出并访问
				Pop(S,p);visit(p->data);
				r = p;					//记录最近访问过的结点
				p = NULL;				//访问结束后,重置p指针(该结点的父亲结点只有左孩子)
			}
		}
	}
}