按层次遍历二元树

来源:互联网 发布:造价师用什么软件 编辑:程序博客网 时间:2024/05/29 11:43

——按层次遍历二元树

分类: 解题笔记 5061人阅读 评论(1) 收藏 举报
null扩展struct算法

        问题描述:输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。  

        例如输入

   8

  / /

 6 10

/ / / /

5 7 9 11

输出8 6 10 5 7 9 11。

          定义二元树(其实是二元搜索树,但并不遍历算法)的结点为:

view plainprint?
  1. struct BSTreeNode    
  2. {    
  3.     int value;    
  4.     BSTreeNode *left;    
  5.     BSTreeNode *right;    
  6. };    

      思路:利用队列的先进先出,很容易实现。每次取出队列的首元素,然后将其左右子女放入队列中。直至队列为空即可。按这种方式进出队列,正好是按层遍历二元树。

      参考代码:

[cpp] view plaincopyprint?
  1. //函数功能 : 按层次遍历二元树  
  2. //函数参数 : pRoot指向根结点  
  3. //返回值 :   无  
  4. void LevelReverse(BSTreeNode *pRoot)  
  5. {  
  6.     if(pRoot == NULL)  
  7.         return;  
  8.   
  9.     queue<BSTreeNode *> nodeQueue;  
  10.     nodeQueue.push(pRoot);  
  11.     while(nodeQueue.size())  
  12.     {  
  13.         BSTreeNode * pNode = nodeQueue.front(); //取队首元素  
  14.         nodeQueue.pop(); //必须出队列  
  15.         if(pNode->left)  //左子女  
  16.             nodeQueue.push(pNode->left);  
  17.         if(pNode->right) //右子女  
  18.             nodeQueue.push(pNode->right);  
  19.   
  20.         cout<<pNode->value<<' ';  
  21.     }  
  22. }  

       扩展一:上文给出的代码,所有结点都输出在同一行。如果希望仅仅同层结点输出在同一行,该如何修改代码呢?

       思路:如果我们能知道每层的最后一个结点,那么就方便多了,输出每层最后一个结点的同时,输出一个换行符。因此,关键在于如何标记每层的结束。可以考虑在每层的最后一个点之后,插入一个空结点。比如队列中先放入根结点,由于第0层只有一个结点,因此放入一个空结点。然后依次取出队列中的结点,将其子女放入队列中,如果遇到空结点,表明当前层的结点已遍历完了,而队列中放的恰恰是下一层的所有结点。如果当前队列为空,表明下一层无结点,也就说是所有结点已遍历好了。如果不为空,那么插入一个空结点,用于标记下一层的结束。

      参考代码:

[cpp] view plaincopyprint?
  1. void LevelReverse(BSTreeNode *pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return;  
  5.     queue<BSTreeNode *> nodeQueue;    
  6.     nodeQueue.push(pRoot);    
  7.     nodeQueue.push(NULL);   //放入空结点,作为层的结束符  
  8.     while(nodeQueue.size())  
  9.     {  
  10.         BSTreeNode * pNode = nodeQueue.front(); //取队首元素    
  11.         nodeQueue.pop(); //必须出队列   
  12.         if(pNode)  
  13.         {  
  14.             if(pNode->left)  //左子女    
  15.                 nodeQueue.push(pNode->left);    
  16.             if(pNode->right) //右子女    
  17.                 nodeQueue.push(pNode->right);  
  18.             cout<<pNode->value<<' ';    
  19.         }  
  20.         else if(nodeQueue.size()) //如果结点为空并且队列也为空,那么所有结点都已访问  
  21.         {  
  22.             nodeQueue.push(NULL);  
  23.             cout<<endl;  
  24.         }  
  25.     }  
  26. }  

       扩展二:之前讨论的都是从上往下、从左往右遍历二叉树,那么如果希望自下往上、从左右往右遍历二叉树,该如何修改代码呢?

       思路:比较简单的方法,首先遍历二叉树,将所有结点保存在一个数组中,遍历的同时记录每一层在数组中的起止位置。然后根据起止位置,就可以自下往上的打印二叉树的结点。

[cpp] view plaincopyprint?
  1. //每层的起止位置  
  2. struct Pos  
  3. {  
  4.     int begin;  
  5.     int end;  
  6.     Pos(int b, int e): begin(b),end(e) {}  
  7. };  
  8. void LevelReverse(BSTreeNode *pRoot)  
  9. {  
  10.     if(pRoot == NULL)  
  11.         return;  
  12.   
  13.     vector<BSTreeNode*> vec;   //用以存放所有结点  
  14.     vector<Pos> pos;           //用以记录每层的起止位置  
  15.     vec.push_back(pRoot);  
  16.   
  17.     int level = 0;    //树的层数  
  18.     int cur = 0;  
  19.     int last = 1;  
  20.   
  21.     while(cur < vec.size())  
  22.     {  
  23.         last = vec.size();  
  24.         pos.push_back(Pos(cur, last)); //记录当前层的起止位置  
  25.   
  26.         while(cur < last) //遍历当前层的结点,将子女放入数组中  
  27.         {  
  28.             if(vec[cur]->left) //先是左然后是右。如果希望自由向左,交换一下顺序即可  
  29.                 vec.push_back(vec[cur]->left);  
  30.             if(vec[cur]->right)  
  31.                 vec.push_back(vec[cur]->right);  
  32.             cur++;  
  33.         }  
  34.         level++; //层数加1  
  35.     }  
  36.   
  37.     for(int i = level - 1; i >= 0; i--) //自下往上遍历  
  38.     {  
  39.         for(int j = pos[i].begin; j < pos[i].end; j++)  
  40.             cout<<vec[j]->value<<' ';  
  41.         cout<<endl;  
  42.     }  
  43. }  

        本人享有博客文章的版权,转载请标明出处 http://blog.csdn.net/wuzhekai1985

0 0