现在的位置: 首页 > 综合 > 正文

二叉树遍历

2018年11月06日 ⁄ 综合 ⁄ 共 2863字 ⁄ 字号 评论关闭

    二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的。二叉树有前、中、后三种遍历方式,因为树的本身就是用递归定义的,因此采用递归的方法实现三种遍历,不仅代码简洁且容易理解,但其开销也比较大,而若采用非递归方法实现三种遍历,则要用栈来模拟实现(递归也是用栈实现的)。下面先简要介绍三种遍历方式的递归实现,再详细介绍三种遍历方式的非递归实现。

   

一、三种遍历方式的递归实现(比较简单,这里不详细讲解)

1、先序遍历——按照“根节点-左孩子-右孩子”的顺序进行访问。

  1. void pre_traverse(BTree pTree)  
  2. {  
  3.     if(pTree)  
  4.     {  
  5.         printf("%c ",pTree->data);  
  6.         if(pTree->pLchild)  
  7.             pre_traverse(pTree->pLchild);  
  8.         if(pTree->pRchild)  
  9.             pre_traverse(pTree->pRchild);      
  10.     }  
  11. }  

    2、中序遍历——按照“左孩子-根节点-右孩子”的顺序进行访问。

  1. void in_traverse(BTree pTree)  
  2. {  
  3.     if(pTree)  
  4.     {  
  5.         if(pTree->pLchild)  
  6.             in_traverse(pTree->pLchild);  
  7.         printf("%c ",pTree->data);  
  8.         if(pTree->pRchild)  
  9.             in_traverse(pTree->pRchild);   
  10.     }  
  11. }  

    3、后序遍历——按照“左孩子-右孩子-根节点”的顺序进行访问。

  1. void beh_traverse(BTree pTree)  
  2. {  
  3.     if(pTree)  
  4.     {  
  5.         if(pTree->pLchild)  
  6.             beh_traverse(pTree->pLchild);  
  7.         if(pTree->pRchild)  
  8.             beh_traverse(pTree->pRchild);      
  9.         printf("%c ",pTree->data);  
  10. }


1、前序遍历的非递归实现 

根据先序遍历的顺序,先访问根节点,再访问左子树,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历,上图的先序遍历顺序为:ABDECF。非递归的实现思路如下:

对于任一节点P

1)输出节点P,然后将其入栈,再看P的左孩子是否为空;

2)P的左孩子不为空,则置P的左孩子为当前节点,重复1)的操作;

3)P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,看其是否为空;

4)若不为空,则循环至1)操作;

5)如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否为空,重复4)和5)操作;

6)直到当前节点PNULL并且栈空,遍历结束。


void preOrder2(BinTree *root)     //非递归前序遍历 
    {
    stack<BinTree*> s;
    BinTree *p=root;
    while(p!=NULL||!s.empty())
    {
        while(p!=NULL)
        {
            cout<<p->data<<" ";
            s.push(p);
            p=p->lchild;
        }
        if(!s.empty())
        {
            p=s.top();
            s.pop();
            p=p->rchild;
        }
    }
}

 2、中序遍历的非递归实现

根据中序遍历的顺序,先访问左子树,再访问根节点,后访问右子树,而对于每个子树来说,又按照同样的访问顺序进行遍历,上图的中序遍历顺序为:DBEAFC。非递归的实现思路如下:

对于任一节点P

1)P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对当前节点进行相同的处理;

2)P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其是否为空;

3)若不为空,则重复1)和2)的操作;

4)若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为当前节点,看起是否为空,重复3)和4)的操作;

5)直到当前节点PNULL并且栈为空,则遍历结束。

void inOrder2(BinTree *root)      //非递归中序遍历
{
    stack<BinTree*> 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<<p->data<<" ";
            s.pop();
            p=p->rchild;
        }
    }    
} 

3、后序遍历的非递归实现

根据后序遍历的顺序,先访问左子树,再访问右子树,后访问根节点,而对于每个子树来说,又按照同样的访问顺序进行遍历,上图的后序遍历顺序为:DEBFCA。后序遍历的非递归的实现相对来说要难一些,要保证根节点在左子树和右子树被访问后才能访问,思路如下:

对于任一节点P

1)先将节点P入栈;

2)P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;

3)若不满足2)中的条件,则将P的右孩子和左孩子依次入栈,当前节点重新置为栈顶结点,之后重复操作2);

4)直到栈空,遍历结束。

void postOrder3(BinTree *root)     //非递归后序遍历
{
    stack<BinTree*> s;
    BinTree *cur;                      //当前结点 
    BinTree *pre=NULL;                 //前一次访问的结点 
    s.push(root);
    while(!s.empty())
    {
        cur=s.top();
        if((cur->lchild==NULL&&cur->rchild==NULL)||
           (pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
        {
            cout<<cur->data<<" ";  //如果当前结点没有孩子结点或者孩子节点都已被访问过 
              s.pop();
            pre=cur; 
        }
        else
        {
            if(cur->rchild!=NULL)
                s.push(cur->rchild);
            if(cur->lchild!=NULL)    
                s.push(cur->lchild);
        }
    }    
}

转自:

http://blog.csdn.net/ns_code/article/details/12977901

http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

抱歉!评论已关闭.