zoukankan      html  css  js  c++  java
  • 二叉树分层遍历

    首先定义二叉树的存储结构:

      

    1 struct TreeNode {
    2     int val;
    3     TreeNode *left;
    4     TreeNode *right;
    5 
    6     TreeNode(int v, TreeNode* l = NULL, TreeNode *r = NULL)
    7         :val(v), left(l), right(r) {}
    8 };

    1.递归的方法(《编程之美》3.10)

      二叉树本身就带有递归属性,通常我们可以用递归方法解决。假设要访问第k层节点,那么其实可以转皇城分别访问“以该二叉树根节点的左右子节点为根节点的两棵子树”中层次为k-1的节点。此方法需要求出二叉树的深度,其实可以直接访问到二叉树某一层次失败的时候返回就可以了。

      这个方法的问题是递归调用,效率较低。而且对每一层的访问都需要从根节点开始,效率极差。

      最坏的情况下(不平衡树)时间复杂度为O(n^2),空间复杂度O(1)

     1 //输出以root为根节点中的第level层中的所有节点(从左至右),成功返回1
     2 //失败返回0
     3 //root为二叉树根节点
     4 //level为层次数,其中根节点为第0层
     5 int PrintNodeAtLevel(TreeNode *root, int level) {
     6     if (!root || level < 0) return 0;
     7     if (level == 0){
     8         cout<<root->val;
     9         return 1;
    10     }
    11 
    12     return PrintNodeAtLevel(root->left, level - 1) + PrintNodeAtLevel(root->right, level - 1);
    13 }
    14 
    15 //层次遍历二叉树
    16 //root,二叉树的根节点
    17 void LevelOrder(TreeNode *root) {
    18     for (int level = 0; ; level++) {
    19         if (!PrintNodeAtLevel(root, level)) 
    20             break;
    21         cout<<endl;
    22     }
    23 }

    2. 使用数组和两个游标的方法(《编程之美》 3.10)

      在访问k层的时候,我们只需要知道k-1层的信息就足够了,所以在访问第k层的时候,要是能够知道k-1层的节点信息,就不再需要从根节点开始遍历了。

      根据上述分析,可以从根节点出发,依次将每一层的根节点从左往右压入一个数组,并并用一个游标cur记录当前访问的节点,另一个游标last指示当前层次的最后一个节点的下一个位置,以cur===last作为当前层次访问结束的条件,在访问某一层的同时将该层的所有节点的子节点压入数组,在访问完某一层之后,检查是否还有新的层次可以访问,直到检查完所有的层次(不再有新的节点可以访问)

      这种方法需要一个vector一直存储所有节点,空间效率较差。

      时间复杂度为O(n),空间复杂度为O(n)

     1 void LevelOrder(TreeNode *root) {
     2     if (root == NULL) return;
     3     vector<TreeNode *> vec; //这里使用stl中的vector代替数组,可利用到
     4                             //其动态扩展的属性
     5     vec.push_back(root);
     6     int cur = 0, last = vec.size();
     7     while (cur < vec.size()) {
     8         last = vec.size();
     9 
    10         while (cur < last) {
    11             cout<<vec[cur]->val;
    12             if (vec[cur]->left) 
    13                 vec.push_back(vec[cur]->left);
    14             if(vec[cur]->right)
    15                 vec.push_back(vec[cur]->right);
    16             ++cur;
    17         }
    18         cout<<endl;
    19     }
    20 }

    3. 两个队列的方法

      广度优先搜索的思想。使用两个队列,一个记录当前层的节点,另一个记录下一层的节点。输出当前层节点后交换,使下一层的节点称为当前层的节点。

      时间复杂度O(n),空间复杂度O(1)

     1 void LevelOrder(TreeNode *root) {
     2     if (root == NULL) return ;
     3 
     4     queue<TreeNode *> current, next;
     5     
     6     current.push(root);
     7     while (!current.empty()) {
     8         while (!current.empty()) {
     9             TreeNode * p = current.front();
    10             cout<<p->val<<" ";
    11             current.pop();
    12             if (p->left)
    13                 next.push(p->left);
    14             if (p->right)
    15                 next.push(p->right);
    16         }
    17         cout<<endl;
    18         swap(next, current);
    19     }
    20 }

    4.使用一个队列和两个标记的方法

      使用current记录当前节点的数量,nextlevel记录下一层节点的数量。当current==0时就将下一层置为当前层。

      

     1 void LevelOrder(TreeNode *root) {
     2     if (root == NULL) return;
     3 
     4     queue<TreeNode *> q;
     5     q.push(root);
     6     int nextlevel = 0; //记录下一层节点的数量
     7     int current = 1; //记录当前层节点的数量
     8 
     9     while (!q.empty()) {
    10         TreeNode *p = q.front();
    11         q.pop();
    12         --current;
    13         cout<<p->val<<" ";
    14 
    15         if (p->left) {
    16             q.push(p->left);
    17             ++nextlevel;
    18         }
    19         if (p->right) {
    20             q.push(p->right);
    21             ++nextlevel;
    22         }
    23 
    24         if(current == 0) {
    25             cout<<endl;
    26             swap(current, nextlevel);
    27         }
    28     }
    29 }

      

    5. 使用一个队列加一个标记的方法

      用队列暂存储节点,每当一层节点进入队列,就在最后加入一个空指针表示当前层结束。

     1 void LevelOrder(TreeNode *root) {
     2     if (root == NULL) return;
     3 
     4     queue<TreeNode *> q;
     5     q.push(root);
     6     q.push(0);
     7     while (!q.empty()) {
     8         TreeNode *p =q.front();
     9         q.pop();
    10         if (p) {
    11             cout<<p->val<<" ";
    12             if (p->left)
    13                 q.push(p->left);
    14             if (p->right)
    15                 q.push(p->right);
    16             //当发现空指针(结束信号时),要检查队列是够还有节点
    17             //如果没有的话还插入新的结束信号,则会造成死循环
    18         } else if (!q.empty()) {
    19             q.push(0);
    20             cout<<endl;
    21         }
    22     }
    23 }

     参考资料:

         1.《编程之美》

         2. 《剑指offer》

         2. http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html

  • 相关阅读:
    UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
    Codeforces 482E ELCA (LCT)
    Codeforces 798D Mike and distribution (构造)
    AtCoder AGC017C Snuke and Spells
    HDU 6089 Rikka with Terrorist (线段树)
    HDU 6136 Death Podracing (堆)
    AtCoder AGC032D Rotation Sort (DP)
    jenkins+python+kubectl实现批量更新k8s镜像
    Linux 下载最新kubectl版本的命令:
    jenkins X 和k8s CI/CD
  • 原文地址:https://www.cnblogs.com/vincently/p/4230253.html
Copyright © 2011-2022 走看看