二叉树分层遍历

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

  

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.使用一个队列加一个标记的方法

  

 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. http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html

时间: 2024-10-25 09:28:33

二叉树分层遍历的相关文章

【LeetCode-面试算法经典-Java实现】【103-Binary Tree Zigzag Level Order Traversal(二叉树分层Z字形遍历)】

[103-Binary Tree Zigzag Level Order Traversal(二叉树分层Z字形遍历)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alt

编程之美-分层遍历二叉树

问题:给定一个二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号.那么分层遍历如图的二叉树,正确的输出应该为: <span style="font-size:14px;">1 2 3 4 5 6 7 8</span> 书中还给出了问题2:打印二叉树中的某层次的节点(从左到右),其中根结点为第0层,成功返回true,失败返回false 分析与解法 关于二叉树的问题,由于其本身固有的

分层遍历二叉树算法

分层遍历二叉树的集中情况 从上而下的打印 vector<vector<int>> printLevel(TreeNode *root) {          vector<vector<int>>  ret;     if(root == NULL) return ret;          queue<TreeNode *> q;     int size;     q.push_back(root);     while(!q.empty()

3.10 分层遍历二叉树

题目1:写一个函数,打印二叉树中某层次的节点(从左到右),其中根节点为第0层. 思路:利用递归算法,思想是:要求访问二叉树中第k层的节点,那么其实就是要访问"以该二叉树根节点的左右子节点为根节点的两颗子树"中层次为k-1的节点 代码: struct pNode { int data; pNode *lChild; pNode *rChild; }; int printNodeAtLevel(pNode *root, int level) { if(root == NULL || lev

编程之美问题之二叉树层序遍历多种解法

二叉树的层序遍历(要求区分层,例如每层遍历完输出换行) 单单层序遍历非常简单,一个队列就搞定了,但是区分层则要麻烦些.总的思路无非就是在每次print的时候,要能通过某个东西 区分出当前节点是否是一层最后一个节点,或者下一层的最后一个节点,感觉有点类似于机器学习中找个区分度明显的特征: 1.自己的解法,在单队列基础上,输入队列的数据添加一个标志 ,LevelHeaded,同时,在后面插入两个孩子的时候,判断是否这次输出的是队头,如果是的话,先插 个队头标志,再插入孩子,而且插入一次之后,后面不能

数据结构第三部分:树与树的表示、二叉树及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树、集合及其运算

参考:浙大数据结构(陈越.何钦铭)课件 1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找——方法一:顺序查找(时间复杂度O(n)) int

【树4】二叉树的遍历

简介 遍历二叉树就是按照某种顺序,将树中的结点都枚举一遍,且每个结点仅仅访问一次.因为树不是线性的结构,遍历不像线性表那样简单,因此他的遍历需要特点的算法来完成. 从某种角度讲,对二叉树的遍历就是将树形结构转换为线性结构的操作. 二叉树的遍历方法主要有如下几种: 先序遍历:先访问root结点,再先序遍历左子树,再先序遍历右子树. 中序遍历:先中序遍历左子树,再访问root结点,再中序遍历右子树. 后序遍历:先后序遍历左子树,再后序遍历右子树,再访问root结点. 层遍历:从上到下,从左到右,一层

树、二叉树、遍历二叉树的总结

首先介绍树: 如上图所示就是一棵树,先介绍树的几个关键名词: 节点:A.B.C.D等都叫节点 节点的度:节点有几个分支,就叫节点的度,比如节点B有2个分支,那B的度为2 终端节点(叶子):没有分支的节点,如E.F.G.H 非终端节点:有分支的节点,如A.B.D.C 节点的层次:自上而下排列层次,A为1层,B为2层,D为3层 树的度:哪个节点的度最大,这个最大的度就是树的度,如图树的度为2 树的深度:简而言之,就是树有几层,如图的树的深度为4 我们接触最多的树是二叉树 二叉树:在计算机科学中,二叉

java生成二叉树和遍历

在java中实现二叉树和链表的方法都是在类中定义该类的对象引用 比如 class Tree { int data; Tree left; Tree right; } 这样的话当我们new一个Tree对象的时候,该对象就拥有了left和right两个对象,这样就起到了连接的 作用,在链表中就是连接了下一个,在树中就相当于边,这样就起到一个接一个的效果.总之,就是吧对象连接起来了. 下面是完整代码 package code; public class TwoTree { public static