二叉树的中序遍历

二叉树的遍历(以中序遍历为例)

1.中序遍历二叉树的操作定义为:

若二叉树为空,则空操作;否则

 

( 1 ) 中序遍历左子树

( 2 ) 访问根结点

( 3 ) 中序遍历右子树

 

我们很容易写出它的递归算法:

void InOrderTraverse(BiNode *pRoot)

{

         if(pRoot!=NULL)

{

                 InOrderTraverse(pRoot->lchild);//中序遍历左子树

         visited(pRoot->data);//访问根结点

                  InOrderTraverse(pRoot->rchild);// 中序遍历右子树

}

}


对于这棵二叉树的中序遍历为:B D A E C

 

我们现有来看看它的非递归算法:

思路:我们遍历二叉树时,要依靠中序遍历的规则:注意在(1)和(3)中是遍历而不是访问,这也就隐含了我们是把左子树看成一个集合的而不是一个结点。那么哪一个结点才是第一个被访问的呢?我们用p来寻找。

当我们用p1指向A时想要访问它,可是发现它有左子树,所以我们要先访问它的左子树于是用p指向了它的左子树。当我们访问p所指的结点时必须就要看看它是否还有左子树要访问,如果它的左子树为空,那么我们就可以访问它了。在我们访问了这个结点之后,我们用同样的方式访问了这个结点的右子树(我们用p指向它的右子树),那么问题就来了,我们该如何回来呢?我们如何访问第一个被访问结点的祖先结点呢?

答案是我们必须把祖先结点一一保存下来。我们还会发现先保存的结点后使用,这符合了栈这个数据结构的特性。因此在遍历的过程中,我们用栈来保存祖先结点。

请看图

 

下面是算法:

while(栈不空或p不空)

{

         while(p不空)

{

入栈,向左

}

if(栈不空)

{

         出栈;

  访问;

向右;

}

}

 

实现

void InOrderTraverse(BiNode *pRoot)

{

if(pRoot==NULL)

return ;

stack<BiNode *> s;

while(s.empty()||p!=NULL)

{

         while(p)

{

s.push(p);

p=p->lchild;

}

if(!s.empty())

{

         p=s.top();

s.pop();

visit(p)->data;

p=p->rchild;

}

}

}

2.在二叉树的遍历过程中,我们需要做的一件事是要保存访问结点的祖先结点。但是我们还有一个方法可以不用存储祖先结点。那就是可以利用叶子结点的右子树指针来指向这个祖先结点,(你可以发现当我们想要祖先结点的时候都发生在访问了叶子结点之后)。

 

问题: 不使用递归和栈来中序遍历二叉树。

我们用叶子结点的空指针记录当前结点的位置,然后一旦遍历到了叶子结点发现叶子结点的右指针不为空(指向的是当前结点),那么就认为当前结点的左子树已经遍历完成,利用了线索二叉树的思想

 

如果当前结点为空,程序退出。

 

如果当前结点不空

 

  1. 如果当前结点的左儿子为空,那么输出当前结点,当前结点置为当前结点的右儿子

  2. 如果当前结点的左儿子不空,找到当前结点的左子树的最右叶子结点。

  1. 若最右的叶子结点的右儿子指针为空,则让其指向当前结点,当前结点置为当前结点的左儿子

  2. 若最右的叶子结点的右儿子指针不空(指向当前结点),说明当前结点的左子树已经遍历完成,将右儿子指针置为空并将当前结点的置为当当前结点的右子树

3.  void MorrisTraversal(BiNode *pRoot)

4.  {

5.     BiNode *current;

6.     BiNode *pre;

7.     if(pRoot==NULL) return ;

8.     current=pRoot;

9.     while(current!=NULL)//树不为空,判断这个结点的左子树是否为空

10.           {

11.                    

12.          

13.                     if(current->lchild==NULL)//左子树为空。

14.                     {

15.                              visit(current->data);

16.                              current=current->rchild;

17.                     }

18.                     else//左子树不为空就要找左子树的最右的那个结点

19.                     {

20.                              pre=current->lchild;

21.                              while(pre->rchild!=NULL||pre->rchild!=current)

22.                              {

23.                                       pre=pre->rchild;

24.                              }

25.                              if(pre->rchild==current)//说明已经遍历完了pre的左子树

26.                              {

27.                                       pre->rchild=NULL;

28.                                       visit(current->data);

29.                                       current=current->rchild;

30.                              }

31.                              else

32.                              {

33.                                       pre->rchild=current;

34.                                       current=current->lchild;

35.                              }

36.                             

37.                     }

38.                    

39.           }

40.   

41.  }

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值