非递归前,中,后序遍历二叉树

 

相比递归遍历二叉树,非递归遍历二叉树稍难一些,而又数非递归后序遍历二叉树更难。在我通过与这段时间所学数据结构相结合,学习和了解了非递归遍历二叉树的方法,

这里三种遍历方式都会用到栈,利用栈的逐层压栈与先进后出的特点,类似于用代码实现了递归遍历二叉树的基本方法。非递归二叉树的遍历个人认为注重的是思想,代码实现思想,呈现思维过程,所以在这里,我先是用画图的方式模拟非递归遍历二叉树时的步骤以及栈中的元素变化,最后通过代码将这个过程来实现的.

 

 

 

(1)前序遍历顺序是根节点-----左节点-----右节点,我们首先从根节点root开始边压栈边打印,从他们的每个左节点逐层向下压栈,一直压到最左叶子结点的左孩子

(2)取栈顶结点,依次访问他们的右结点,下面的右节点访问完表示下面的子树都访问完,然后pop出栈,再去栈顶结点,继续访问它的右节点,一直到访问根节点的右树,根节点的右树访问完之后,pop出栈,此时栈中节点为空了,表示整个二叉树已经遍历完。

下面是给的两种代码的实现,思想相同.

前序遍历

 

//第一种实现代码
void PrevOrderNonR(Node* root)
{
    stack<Node*> tmp;
    Node* cur = root;
    //如果栈中为空,则表示整个二叉树都已访问
    while(tmp.empty())
    {
       //逐层压入最左节点
       //前序边压栈边打印
        while(cur)
        {
            cout<<cur._data<<" ";
            tmp.push(cur);
            cur = cur->_left;
        }
        //cur为NULL表示遍历到最左节点的左孩子
        //开始逐层向上访问他们的右节点
        Node* Top = tmp.top();
        tmp.poo();
        cur = Top->_right;
    }
}

 

另一种方法是右节点和左节点一起遍历,不一样的是左节点不用压栈,直接打印,每次压入其根节点的右孩子,到最后叶子节点后,去栈顶,并出栈,依次向上打印右树

 

不过思想还是相同,代码如下:

 

void PrevOrderNonR(Node* root)
{
    stack<Node*> tmp;
    Node* cur = root;
    while(tmp.empty())
    {
        if(cur->_right)
            tmp.push(cur->_right);
        if(cur->_left)
            cout<<cur._left<<" ";
        else//左树遍历完后开始取栈顶
        {
            cur = tmp.top();
            tmp.pop();
        }
    }
    cout<<endl;
}

 

中序遍历

如果前序你能自己实现,那么相信你中序也可以实现,因为他们的思想真的类似。。。这里不多赘述中序的过程,直接贴上代码,

 

//在出栈到根节点时,先是将root值赋给cur,然后cur=cur->_right即开始遍历根节点的右子树,在后面出栈时顺序为:①取栈顶指针赋给cur②打印栈顶元素的值③pop掉栈顶元素,开始向上走③cur取其右孩子指针,开始遍历右节点

void _InOrder_NonR(Node* root)
	{
		if (root == NULL)
			return;
		stack<Node*> tmp;
		Node* cur = root;
		while(cur||!tmp.empty())
		{
			while(cur)
			{
				tmp.push(cur);
				cur = cur->_left;
			}
			//到最左叶子结点,开始打印和遍历右节点
			cur = tmp.top();
			cout<<cur._data<<" ";
			tmp.pop();
			cur = cur->_right;
		}
	}


相比较前两种的遍历方法,这里的后序会比较难,但也不是很难,有一个小坑,在思考和代码实现中要多加考虑。

 

后序遍历顺序是 左节点------右节点------根节点

根据前面两种的类似方法,我们里所以当是先从根节点开始,逐层向下,压入他们的最左节点,然后逐层向上依次访问他们的右节点,最后再是打印他们的根节点。

先下,然后上右,然后上右,一直到根节点也如此,最后栈内节点为空,遍历结束。

在这里,我们需要再遍历完他们的右节点后在返回到根节点时,需要再设置一个prev变量,来保存他们的前一访问节点,以便能找到回家的路^ ^

坑来了,从右节点返回到根节点这里需要再判断一次,前一位置是否访问的是他的右孩子,如果是右孩子,则向上出栈,如果不是则访问右节点,如果没有判断,那么

将会在这里死循环一直在根节点和右节点之间无限循环。 

后序遍历需要注意的就这么多了,代码呈上,如下:

 

void _PostOrder_NonR(Node* root)
	{
	  if(NULL == root)
        return;
      stack<Node*> tmp ; 
      Node* cur = root;
      Node* prev = NULL;
      //先遍历压栈到最左节点
      while(cur)
      {
          tmp.push(cur);
          cur = cur->_left;
      }
        //逐层向上访问右节点和根节点
      while(!tmp.empty())
        {
          cur = tmp.top();
          tmp.pop();
          //如果右节点为空或者之前已经访问过右节点
          //直接打印当前根节点然后在下次循环中pop出栈,访问上面的节点
          if(cur->_right == NULL || cur->_right == prev)
          {
              cout<<cur._data<<" ";
              prev = cur;
          }
          //else(右节点存在&&右节点没被访问过)
          else 
          {
              while(cur)
              {
                  tmp.push(cur);
                  cur = cur->_left;
              }
          }
          cout<<endl;
      }
    }

 

 

 

 

 

这就是非递归前,中,后序遍历二叉树的基本思想和代码实现,希望对你有所帮助  PS:数据结构注重的是思维,其次是代码的实现,代码实现也是思维的呈现.

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值