二叉树的深度优先dfs遍历(前序、中序和后序;递归与非递归)

二叉树本身就是用递归定义的,因此采用递归方法实现dfs的三种遍历不仅容易理解而且代码简洁。

若用非递归实现,则要采用栈去模拟:保存计算的上下文,使得计算在返回上一级时有路可循。注意每一个结点都要当作根结点来看待。

//前序遍历
//递归实现:根左右
void preOrder1(BinTree *root)
{
    if (root != NULL)
    {
        cout<data<lchild);
        preOrder1(root->rchild);
    }
}

//非递归实现
/*注意,如前所述,我们将二叉树的每一个结点都看作根结点。因此,从整个二叉树的根结点root出发,一路向左,遇到的每一个结点都立即访问(它是根,同时也是其父亲的左子树的根,所以这个过程访问了“根和左”)并入栈,直到不能再左,转向右(这个“右”上哪找呢?当然是父亲的右儿子。父亲去哪里找呢?当然是栈里),将这个右儿子当成新的根结点重复上述过程,直到栈为空且当前根结点也为空。*/
void preOrder2(BinTree *root)
{
	stack s;
	BinTree *p=root;
 	while (p!=NULL || !s.empty())
 	{
  		//一路向左
  		while (p!=NULL)
		{      
			cout<data<lchild;
		}
 
		//当不能再左时,开始向右
  		if (!s.empty())
  		{
   			p=s.top();//从栈里面取出根结点
   			s.pop();
   			p=p->rchild;            //作为新的根结点
  		}
 	}
 }

//中序遍历
//递归实现:左根右
void inOrder1(BinTree *root)
{
	if (root != NULL)
	{
  		inOrder1(root->lchild);
  		cout<data<rchild);
 	}
}

//中序遍历 
//非递归实现
/*与前序遍历类似,但是,根结点进栈时不访问(否则就成了前序遍历),根结点弹栈时才访问(左根右)。*/
void inOrder2(BinTree *root)
{
	stack s;
	BinTree *p=root;
 
	while (p!=NULL || !s.empty())
	{
  		//一路向左
 		while (p!=NULL)
 		{
 			s.push(p);
 			p=p->lchild;
 		}
 
  		//当不能再左时,访问根结点,向右
  		if (!s.empty())
  		{
   			p=s.top();
   			cout<data<rchild;
  		}
	}
}

//后序遍历
//递归实现:左右根
void postOrder1(BinTree *root)
{
	if (root != NULL)
	{
		postOrder1(root->lchild);
		postOrder1(root->rchild);
		cout<data< s;
	BinTree *p=root;
 
	poNode *temp;
 
	while (p!=NULL || !s.empty())
	{
 		//一路向左直到不能再左
		while (p!=NULL)
		{
			temp = (poNode *)malloc(sizeof(poNode));
			temp->btnode = p;
			temp->isFirst = True;	 //第一次进栈标记
			s.push(temp);
 
			p=p->lchild;
		}
 
		if (!s.empty())
		{
			temp = s.top();	 //此时还不能访问,否则就是中序遍历了
			s.pop();
 
			//如果是第一次进栈,那还需要再进栈一次,之后以它的右儿子为新的根结点
			if (temp->isFirst == true)
			{
				temp->isFirst = false;
				s.push(temp);
				p = temp->btnode->rchild;
 			}
			else
			{
				cout<btnode->data<

总结 :所有结点都看作根结点,关键在于何时访问。前序:入栈时访问;中序:第一次退栈时访问;后序:第二次退栈时访问。

你可能感兴趣的:(二叉树)