二叉树的非递归遍历及层次遍历

前面简答介绍了二叉树的基本操作,包括二叉树的建立,销毁,递归遍历,以及其他一些常见的递归算法,现在集中讨论一下二叉树的层次遍历和非递归遍历。

二叉树的层次遍历要用到队列,前序、中序和后序非递归遍历要用到栈,这里我就不自己写队列和栈了,直接使用C++标准库中的容器适配器queue和stack。

1、 二叉树的层次遍历

二叉树的层次遍历类似图的广度优先遍历,都用到了队列。

基本思路:

(1)根结点非空,则入队列

(2)队列非空,队首元素出队列,输出结点值,若结点有左孩子,左孩子入队列;若结点有右孩子,右孩子也入队列。

(3)重复步骤(2)直到队列为空

显然通过以上步骤,得到的是二叉树从上至下,从左到右的层次遍历序列。实现代码如下:

[cpp]  view plain  copy
  1. //二叉树的层次遍历,用到了队列   
  2. void levelOrderTraverse(const BiTree& T)  
  3. {  
  4.     queue<BiTree> q;  
  5.     BiTree p = NULL;  
  6.       
  7.     if(T)//若根结点非空,则入队列   
  8.     {  
  9.         q.push(T);  
  10.     }  
  11.     while(!q.empty())//队列非空   
  12.     {  
  13.         p = q.front();  
  14.         q.pop();  
  15.         cout<<p->data<<" ";  
  16.         if(p->lchild)//左孩子不空,入队列   
  17.         {  
  18.             q.push(p->lchild);  
  19.         }  
  20.         if(p->rchild)//右孩子不空,入队列   
  21.         {  
  22.             q.push(p->rchild);  
  23.         }  
  24.     }   
  25. }  

2、二叉树的先序非递归遍历

二叉树的先序非递归遍历比较简单,基本思路是先输出结点值,再入栈,然后遍历左子树。退栈时,遍历栈顶结点的右子树,看代码:

[cpp]  view plain  copy
  1. //二叉树的先序非递归遍历   
  2. void iterativePreOrderTraverse(const BiTree& T)  
  3. {  
  4.     stack<BiTree> s;  
  5.     BiTree p = T;  
  6.       
  7.     while(p || !s.empty())//p非空,或栈非空  
  8.     {  
  9.         if(p)  
  10.         {  
  11.             //输出根结点,根结点入栈,遍历左子树   
  12.             cout<<p->data<<" ";  
  13.             s.push(p);  
  14.             p = p->lchild;  
  15.         }  
  16.         else  
  17.         {  
  18.             //根结点退栈,遍历右子树   
  19.             p = s.top();  
  20.             s.pop();  
  21.             p = p->rchild;//转右孩子结点   
  22.         }  
  23.     }  
  24. }  

3、二叉树的中序非递归遍历

二叉树的中序非递归遍历也很简单,和先序不同的是,中序是先进栈,再遍历左子树;出栈时,才输出结点值,然后遍历右子树,代码如下:

[cpp]  view plain  copy
  1. //二叉树的中序非递归遍历   
  2. void iterativeInOrderTraverse(const BiTree& T)  
  3. {  
  4.     stack<BiTree> s;  
  5.     BiTree p = T;  
  6.       
  7.     while(p || !s.empty())//p非空,或栈非空  
  8.     {  
  9.         if(p)  
  10.         {  
  11.             //根指针进栈 ,遍历左子树   
  12.             s.push(p);    
  13.             p = p->lchild;  
  14.         }  
  15.         else  
  16.         {  
  17.             //根指针退栈,访问根结点,遍历右子树   
  18.             p = s.top();  
  19.             s.pop();  
  20.             cout<<p->data<<" ";  
  21.             p = p->rchild;  
  22.         }  
  23.     }  
  24. }  

4.二叉树的后序非递归遍历

二叉树的后序非递归遍历,比先序和中序非递归遍历,稍微复杂点。因为后序遍历的顺序是左子树->右子树->根结点,所以我们在遍历过程中得标记左右子树的状态。这里我们用一个bool变量标识结点p的右子树遍历状态,false表示右子树未遍历,true则表示右子树已遍历。代码如下:

(1)版本1

[cpp]  view plain  copy
  1. //二叉树的后序非递归遍历   
  2. void iterativePostOrderTraverse(const BiTree& T)  
  3. {  
  4.     stack<pair<BiTree,bool> > s;  
  5.     BiTree p = T;  
  6.       
  7.     while(p || !s.empty())  
  8.     {  
  9.         if(p)  
  10.         {  
  11.             s.push(make_pair(p,false));//false表示根结点p的右子树未访问   
  12.             p = p->lchild;  
  13.         }  
  14.         else  
  15.         {  
  16.             if(s.top().second == false)//根结点的右子树未访问   
  17.             {  
  18.                 s.top().second = true;//标志右子树为已访问   
  19.                 p = s.top().first->rchild;//遍历右子树   
  20.             }  
  21.             else//右子树已访问   
  22.             {  
  23.                 cout<<s.top().first->data<<" "//输出根结点值   
  24.                 s.pop();//根结点出栈   
  25.             }  
  26.         }     
  27.     }  
  28. }  
(2)版本2
[cpp]  view plain  copy
  1. //后序非递归遍历的另一个版本   
  2. void anotherIterativePostOrderTraverse(const BiTree& T)  
  3. {  
  4.     stack<pair<BiTree,bool> > s;  
  5.     BiTree p = T;  
  6.       
  7.     do  
  8.     {  
  9.         while(p)  
  10.         {  
  11.             s.push(make_pair(p,false));  
  12.             p = p->lchild;  
  13.         }  
  14.           
  15.         while(!s.empty() && s.top().second == true)  
  16.         {  
  17.             cout<<s.top().first->data<<" ";  
  18.             s.pop();  
  19.         }  
  20.           
  21.         if(!s.empty())  
  22.         {  
  23.             s.top().second = true;  
  24.             p = s.top().first->rchild;  
  25.         }  
  26.     }while(!s.empty());  
  27. }  

注:我们来分析一下,后序非递归遍历的执行过程。举一个简单的例子吧,使用根结点为A,其左右子树分别为B、C的树来讲解版本(1)的执行过程。

(1)初始时,p =T,接着执行循环,若根结点非空,则<p,false>入栈,表示根结点p的右子树还未遍历,同时置p为其左指针,遍历左子树。若根结点为空(此时栈也为空),循环条件不满足,直接结束。

(2)在接下来的循环中,若p为空则看栈顶结点状态。若其右子树未遍历,则遍历其右子树(p值发生改变),否则直接输出结点值,并弹出栈顶结点(p值未改变)。

(3)p=A,<A,false>入栈,p=A->lchild=B;

p=B,<B,false>入栈,p=NULL;

p=NULL,栈非空,且栈顶结点B的右子树未访问,置true,然后访问B的右子树,p=B->rchild=NULL;

p=NULL,栈非空,且栈顶结点B的右子树已访问,输出结点B,弹出栈顶结点B,注意此时p==NULL,因为这个过程p的值未改变。

p=NULL,栈非空,且此时栈顶结点A的右子树未访问,置true,然后访问A的右子树,p=A->rchild=C;

p=C,非空,<C,false>入栈,p = C->lchild=NULL;

p=NULL,栈非空,栈顶元素C的右子树为访问,置true,然后访问C的右子树,p=C->rchild=NULL;

p=NULL,栈非空,栈顶元素C的右子树已访问,输出结点C,弹出栈顶元素C。

p=NULL,栈非空,栈顶元素A的右子树已访问,输出结点A,弹出栈顶元素A。

p=NULL,此时栈已为空。

(4)注意到在上述的分析过程中,我们发现当p的值为NULL,出栈,p的值未改变,此时我们不用判断p的值,可以直接判断栈顶元素的右子树的访问状态,于是调整循环结构就得到了版本(2)。但是它们原理都是一样的。

5、完整测试代码

[cpp]  view plain  copy
  1. #include <cstdlib>  
  2. #include <iostream>  
  3. #include <stack>  
  4. #include <queue>  
  5.   
  6. using namespace std;  
  7.   
  8. //二叉树定义   
  9. typedef char ElementType;  
  10.   
  11. typedef struct BiTreeNode  
  12. {  
  13.     ElementType data;  
  14.     struct BiTreeNode* lchild;  
  15.     struct BiTreeNode* rchild;  
  16. }BiTreeNode, *BiTree;  
  17.   
  18. //递归的建立一棵二叉树   
  19. //输入为二叉树的先序序列   
  20. void createBiTree(BiTree &T)  
  21. {  
  22.     char data;  
  23.     data = getchar();  
  24.     if(data == '#')  
  25.     {  
  26.         T = NULL;  
  27.     }  
  28.     else  
  29.     {  
  30.         T = new BiTreeNode;  
  31.         T->data = data;  
  32.         createBiTree(T->lchild);  
  33.         createBiTree(T->rchild);  
  34.     }  
  35. }  
  36.   
  37. //递归销毁一棵二叉树  
  38. void destroyBiTree(BiTree &T)  
  39. {  
  40.     if(T)  
  41.     {  
  42.         destroyBiTree(T->lchild);  
  43.         destroyBiTree(T->rchild);  
  44.         delete T;  
  45.         T = NULL;  
  46.     }  
  47. }  
  48.   
  49. //二叉树的层次遍历,用到了队列   
  50. void levelOrderTraverse(const BiTree& T)  
  51. {  
  52.     queue<BiTree> q;  
  53.     BiTree p = NULL;  
  54.       
  55.     if(T)//若根结点非空,则入队列   
  56.     {  
  57.         q.push(T);  
  58.     }  
  59.     while(!q.empty())//队列非空   
  60.     {  
  61.         p = q.front();  
  62.         q.pop();  
  63.         cout<<p->data<<" ";  
  64.         if(p->lchild)//左孩子不空,入队列   
  65.         {  
  66.             q.push(p->lchild);  
  67.         }  
  68.         if(p->rchild)//右孩子不空,入队列   
  69.         {  
  70.             q.push(p->rchild);  
  71.         }  
  72.     }   
  73. }  
  74.   
  75. //二叉树的先序非递归遍历   
  76. void iterativePreOrderTraverse(const BiTree& T)  
  77. {  
  78.     stack<BiTree> s;  
  79.     BiTree p = T;  
  80.       
  81.     while(p || !s.empty())//p非空,或栈非空  
  82.     {  
  83.         if(p)  
  84.         {  
  85.             //输出根结点,根结点入栈,遍历左子树   
  86.             cout<<p->data<<" ";  
  87.             s.push(p);  
  88.             p = p->lchild;  
  89.         }  
  90.         else  
  91.         {  
  92.             //根结点退栈,遍历右子树   
  93.             p = s.top();  
  94.             s.pop();  
  95.             p = p->rchild;//转右孩子结点   
  96.         }  
  97.     }  
  98. }  
  99.   
  100. //二叉树的中序非递归遍历   
  101. void iterativeInOrderTraverse(const BiTree& T)  
  102. {  
  103.     stack<BiTree> s;  
  104.     BiTree p = T;  
  105.       
  106.     while(p || !s.empty())//p非空,或栈非空  
  107.     {  
  108.         if(p)  
  109.         {  
  110.             //根指针进栈 ,遍历左子树   
  111.             s.push(p);    
  112.             p = p->lchild;  
  113.         }  
  114.         else  
  115.         {  
  116.             //根指针退栈,访问根结点,遍历右子树   
  117.             p = s.top();  
  118.             s.pop();  
  119.             cout<<p->data<<" ";  
  120.             p = p->rchild;  
  121.         }  
  122.     }  
  123. }  
  124.   
  125. //二叉树的后序非递归遍历   
  126. void iterativePostOrderTraverse(const BiTree& T)  
  127. {  
  128.     stack<pair<BiTree,bool> > s;  
  129.     BiTree p = T;  
  130.       
  131.     while(p || !s.empty())  
  132.     {  
  133.         if(p)  
  134.         {  
  135.             s.push(make_pair(p,false));//false表示根结点p的右子树未访问   
  136.             p = p->lchild;  
  137.         }  
  138.         else  
  139.         {  
  140.             if(s.top().second == false)//根结点的右子树未访问   
  141.             {  
  142.                 s.top().second = true;//标志右子树为已访问   
  143.                 p = s.top().first->rchild;//遍历右子树   
  144.             }  
  145.             else//右子树已访问   
  146.             {  
  147.                 cout<<s.top().first->data<<" "//输出根结点值   
  148.                 s.pop();//根结点出栈   
  149.             }  
  150.         }     
  151.     }  
  152. }  
  153.   
  154. //后序非递归遍历的另一个版本   
  155. void anotherIterativePostOrderTraverse(const BiTree& T)  
  156. {  
  157.     stack<pair<BiTree,bool> > s;  
  158.     BiTree p = T;  
  159.       
  160.     do  
  161.     {  
  162.         while(p)  
  163.         {  
  164.             s.push(make_pair(p,false));  
  165.             p = p->lchild;  
  166.         }  
  167.           
  168.         while(!s.empty() && s.top().second == true)  
  169.         {  
  170.             cout<<s.top().first->data<<" ";  
  171.             s.pop();  
  172.         }  
  173.           
  174.         if(!s.empty())  
  175.         {  
  176.             s.top().second = true;  
  177.             p = s.top().first->rchild;  
  178.         }  
  179.     }while(!s.empty());  
  180. }  
  181.   
  182. int main(int argc, char *argv[])  
  183. {  
  184.     BiTree T = NULL;  
  185.       
  186.     createBiTree(T);//建立二叉树 如输入AB#D##CE###   
  187. //  createBiTreeWithGenList(T);//如输入A(B(,D),C(E))#  
  188.   
  189.     cout<<"levelOrder: ";  
  190.     levelOrderTraverse(T);  
  191.     cout<<endl;  
  192.       
  193.     cout<<"preOrder: "//先序遍历   
  194. //  preOrderTraverse(T);  
  195.     iterativePreOrderTraverse(T);  
  196.     cout<<endl;  
  197.       
  198.     cout<<"inOrder: ";//中序遍历   
  199. //  inOrderTraverse(T);  
  200.     iterativeInOrderTraverse(T);  
  201.     cout<<endl;  
  202.       
  203.     cout<<"postOrder: ";//后序遍历   
  204. //  postOrderTraverse(T);  
  205. //  iterativePostOrderTraverse(T);  
  206.     anotherIterativePostOrderTraverse(T);  
  207.     cout<<endl;  
  208.       
  209.     destroyBiTree(T);//销毁二叉树,释放空间   
  210.       
  211.     system("PAUSE");  
  212.     return EXIT_SUCCESS;  
  213. }  

注:测试代码中的一些其他函数请看二叉树的基本操作: http://blog.csdn.net/sysu_arui/article/details/7865876

猜你喜欢

转载自blog.csdn.net/ds1130071727/article/details/80401710