博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二叉树的非递归遍历(递归和非递归)
阅读量:6938 次
发布时间:2019-06-27

本文共 3784 字,大约阅读时间需要 12 分钟。

二 叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是 递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中, 前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。

一.前序遍历

   前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。

  1.递归实现

[cpp] 
  1. void pre_order(BTree *root)    
  2. {    
  3.      if(root != NULL)//必不可少的条件,递归的出口    
  4.      {    
  5.         printf("%2c",root->key);    
  6.         pre_order(root->lchild);    
  7.         pre_order(root->rchild);    
  8.   
  9.      }    
  10. }    

 2.非递归实现

    根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:

     对于任一结点P:

     1)访问结点P,并将结点P入栈;

     2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;

     3)直到P为NULL并且栈为空,则遍历结束。

[cpp] 
  1. //非递归前序遍历   
  2. void pre_order(BTree *root)       
  3. {  
  4.     stack<BTree*> s;  
  5.     BTree *p = root;  
  6.     while (p != NULL || !s.empty()) {  
  7.         while(p != NULL) {  
  8.             cout<<p->data<<" ";  
  9.             s.push(p);  
  10.             p = p->lchild;  
  11.         }  
  12.         if (!s.empty()) {  
  13.             p = s.top();  
  14.             s.pop();  
  15.             p = p->rchild;  
  16.         }  
  17.     }  
  18. }  

二.中序遍历

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

    1.递归实现

[cpp] 
  1. void in_order(BTree* root)    
  2. {    
  3.     //必不可少的条件,递归的出口   
  4.      if(root != NULL)   
  5.      {    
  6.         in_order(root->lchild);    
  7.         printf("%2c",root->data);    
  8.         in_order(root->rchild);      
  9.      }    
  10. }   

 

 2.非递归实现

    根据中序遍历的顺序,对于任一结点,优先访问其左孩子,而左孩子结点又可以看做一根结点,然后继续访问其左孩子结点,直到遇到左孩子结点为空的结点才进行访问,然后按相同的规则访问其右子树。因此其处理过程如下:

   对于任一结点P,

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

  2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;

  3)直到P为NULL并且栈为空则遍历结束

[cpp] 
  1. //非递归中序遍历   
  2. void in_order(BTree *root)       
  3. {  
  4.     stack<BTree*> s;  
  5.     BTree *p = root;  
  6.     while (p != NULL || !s.empty()) {  
  7.         while(p != NULL) {              
  8.             s.push(p);  
  9.             p = p->lchild;  
  10.         }  
  11.         if (!s.empty()) {  
  12.             p = s.top();  
  13.             cout<<p->data<<" ";  
  14.             s.pop();  
  15.             p = p->rchild;  
  16.         }  
  17.     }  
  18. }  

 三.后序遍历

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

      1.递归实现

[cpp] 
  1. void post_order(BTree* root)    
  2. {    
  3.     //必不可少的条件,递归的出口   
  4.     if(root != NULL)   
  5.     {    
  6.         post_order(root->lchild);    
  7.         post_order(root->rchild);    
  8.         printf("%2c",root->data);    
  9.     }    
  10. }      

 

 2.非递归实现

       后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍两种思路。

      第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶。

方 法:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子 或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈 顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

[cpp] 
  1. //非递归后序遍历  
  2. void post_order(BTree* root)       
  3. {  
  4.     stack<BTree*> s;  
  5.     //当前结点  
  6.     BTree *cur = NULL;     
  7.     //前一次访问的结点   
  8.     BTree *pre = NULL;        
  9.     s.push(root);  
  10.     while(!s.empty()) {  
  11.         cur = s.top();  
  12.         if( (cur->lchild == NULL && cur->rchild == NULL) ||  
  13.             (pre != NULL && (pre == cur->lchild || pre == cur->rchild)))  
  14.         {  
  15.             //如果当前结点没有孩子结点或者孩子节点都已被访问过   
  16.             cout<<cur->data<<" ";                  
  17.             s.pop();  
  18.             pre = cur;   
  19.         } else {  
  20.             if(cur->rchild != NULL)   
  21.                 s.push(cur->rchild);  
  22.             if(cur->lchild!=NULL)     
  23.                 s.push(cur->lchild);  
  24.         }  
  25.     }      
  26. }  

四、层次遍历

//采用STL中的queue处理

[cpp] 
    1. #include <queue>  
    2. void layerOrder(BTree *tree)  
    3. {  
    4.     if (tree == NULL)  
    5.         return;  
    6.   
    7.     queue<BTree *> q;  
    8.     q.push(tree);  
    9.       
    10.     BTree *p = NULL;  
    11.     while (!q.empty())  
    12.     {  
    13.         p = q.front();  
    14.         visit(p);          
    15.         q.pop();  
    16.         if (p->lchild != NULL)  
    17.             q.push(p->lchild);  
    18.         if (p->rchild != NULL)  
    19.             q.push(p->rchild);  
    20.     }  
    21. }  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/树的深度
 
int 
TreeDepth(BTree* root) 
     
int 
nLeft, nRight; 
     
if
(root == NULL)
//必不可少的条件,递归的出口 
         
return 
0;   
     
nLeft = TreeDepth(root->lchild); 
     
nRight = TreeDepth(root->rchild); 
     
return 
(nLeft > nRight) ? (nLeft + 1):(nRight + 1); 
   
 
//总共节点
 
int 
totalnode(BTree* root) 
     
if
(root != NULL)
//必不可少的条件,递归的出口 
     
         
ntotal ++; 
         
totalnode(root->lchild); 
         
totalnode(root->rchild); 
     
     
return 
ntotal; 
   
 
//叶子节点
int 
leafnode(BTree* root) 
     
if
(root != NULL)
//必不可少的条件,递归的出口 
     
          
if
((root->lchild == NULL) && (root->rchild == NULL) ) 
          
              
nleaf ++; 
          
          
leafnode(root->lchild); 
          
leafnode(root->rchild); 
     
     
return 
nleaf; 
}

 

本文转自夏雪冬日博客园博客,原文链接:http://www.cnblogs.com/heyonggang/p/3366804.html,如需转载请自行联系原作者

你可能感兴趣的文章
shell脚本
查看>>
linux命令学习(30)-parted
查看>>
SSHD连接操作
查看>>
foundation-datepicker-1.5.6 的使用
查看>>
HTML5应用与原生应用之间的差异
查看>>
写更好的代码,还是写更少的代码?
查看>>
行如风 Angular 初识5
查看>>
关于set_new_handler(转载)
查看>>
[硕.Love Python] FibonacciHeap(F堆 & 斐波那契堆)
查看>>
java.lang.NoClassDefFoundError: net/tsz/afinal/htt
查看>>
我的友情链接
查看>>
SpringBoot入门之缓存
查看>>
创新=深刻的底层认识+丰富的想象力
查看>>
linux上安装Oracle 11g R2 标准版 64位
查看>>
Windows开关机、远程命令
查看>>
字符串转成整数
查看>>
思科命令学习之第二篇
查看>>
24点运算
查看>>
高通平台信号强度和质量的log过滤
查看>>
Yii使用CPagination分页
查看>>