简述
二叉树的层序遍历网上大部分都是使用队列的出队和入队来实现的, 这次我用三行代码递归实现二叉树的层序遍历.
层序
下图是一个简单的二叉树, 层序就是一行一行的往下读取, 这个二叉树的层序结果便是:
1234567
(图画的比较丑, 强迫症看着难受, 看官忍一下)
递归分析
要想使用递归, 必须有两个条件:
函数参数类型相同
递归必须有出口
在二叉树中找到上面的两个条件, 与前中后三种遍历一样, 函数参数为节点的, 递归出口是当左右孩子为空的时候. 传入根节点, 然后依次递归访问左右孩子, 直至为空.
重点
那么问题来了, 递归遍历的数据保存到那? 如何做到保存后是层序的顺序?
继续观察这张图
第一层
根节点标记为 1 元素是层序输出的第一个值
第二层
标记为 2 的元素是层序输出的第二个值, 同时他是标记为 1 节点的左孩子
标记为 3 的元素是层序输出的第三个元素, 同时他是标记为 1 的节点的右孩子.
第三层
标记为 4 的元素是输出的第四个元素, 他是标记为 2 节点的左孩子
标记为 5 的元素是输出的第五个元素, 他是标记为 2 节点的右孩子
很容易找到一个规律:
每一个节点左孩子在层序中输出的位置是该节点在层序输出位置的二倍
每一个节点右孩子在层序中输出的位置是该节点在层序输出位置的二倍加一
根节点在层序输出的位置为 1
也就是:
假设当前节点输出的位置是 i, 那么他的左孩子层序输出的位置是 2*i, 他的右孩子在层序输出的位置为 2*i+1
代码实现
根据上面得出的结论, 就可以写出层序遍历的递归代码了, 知道了节点层序输出的位置, 那么遍历时候直接保存到指定位置, 等所有节点遍历结束后再统一输出, 这个与前中后遍历是不一样的.
既然是根据位置去保存, 那么当然是使用数组了, 位置就是数组的下标, 根据下标进行存放, 操作非常方便.
这一段代码, 是把字符二叉树层序遍历
- int tree2str(bitree *b,char *a,int i)
- {
- if(b->left!=NULL)
- {
- tree2str(b->left,a,2*i);
- }
- if(b->right!=NULL)
- {
- tree2str(b->right,a,2*i+1);
- }
- *(a+i)=b->data;
- }
注意
参数 a 为数组的首地址, 调用时候传递参数 i 初始值为 1, 代表第一层, 既就是根界点, 当递归函数执行完毕时候, 所有的元素都在对应的位置, a[0] 元素始终为空, 因为是从 1 开始存放的, 所以调用之后输出的时候应该从 a+1 的位置开始, 字符串结束应该是 \ 0, 输出前补上防错.
(本人测试环境: 系统 Ubuntu16.04LTS 编译器 GCC5.4, 字符串末尾没有添加 \ 0 未出错, 在 vc6.0 会出现烫烫烫烫烫烫烫烫烫)
结束
回到最初, 标题说是三行代码, 实际上为了看的方便在 if 函数后面加了花括号, 我觉得一行代码的标志应该是一个分号, 既一个语句; 所以上面的也算是三行代码了.
如果上面的不算三行代码, 那就看下面
- int tree2str(bitree *b,char *a,int i)
- {
- if(b->left!=NULL) tree2str(b->left,a,2*i);
- if(b->right!=NULL) tree2str(b->right,a,2*i+1);
- *(a+i)=b->data;
- }
好了现在很直观的三行了 [完].
来源: http://blog.csdn.net/haofan_/article/details/79268585