上篇中学习了二叉树的DFS深度优先搜索算法,这次学习另外一种二叉树的搜索算法:BFS,下面看一下它的概念:

有些抽象是不?下面看下整个的遍历过程的动画演示就晓得是咋回事啦:

了解其概念之后,下面看下如何实现它?在正式实现逐层遍历之前,需要解决一个问题,那就是:得知道该树有多少层,也就是树的深度如何计算,下面来解决这个问题:

还是基于上篇的搜索二叉树的代码进行实现:

  1. public class BinarySearchTree {
  2. TreeNode root = null;
  3.  
  4. class TreeNode{
  5. int value;
  6. int position;
  7. TreeNode left = null, right = null;
  8. TreeNode(int value, int position){
  9. this.value = value;
  10. this.position = position;
  11. }
  12. }
  13.  
  14. public void add(int value, int position){
  15. if(root == null){//生成一个根结点
  16. root = new TreeNode(value, position);
  17. } else {
  18. //生成叶子结点
  19. add(value, position, root);
  20. }
  21. }
  22.  
  23. private void add(int value, int position, TreeNode node){
  24. if(node == null)
  25. throw new RuntimeException("treenode cannot be null");
  26. if(node.value == value)
  27. return; //ignore the duplicated value
  28. if(value < node.value){
  29. if(node.left == null){
  30. node.left = new TreeNode(value, position);
  31. }else{
  32. add(value, position, node.left);
  33. }
  34. }else{
  35. if(node.right == null){
  36. node.right = new TreeNode(value, position);
  37. }else{
  38. add(value, position, node.right);
  39. }
  40. }
  41. }
  42.  
  43. //打印构建的二叉搜索树
  44. static void printTreeNode(TreeNode node) {
  45. if(node == null)
  46. return;
  47. System.out.println("node:" + node.value);
  48. if(node.left != null) {
  49. printTreeNode(node.left);
  50. }
  51. if(node.right != null) {
  52. printTreeNode(node.right);
  53. }
  54. }
  55.  
  56. //搜索结点
  57. public int search(int value){
  58. return search(value, root);
  59. }
  60.  
  61. private int search(int value, TreeNode node){
  62. if(node == null)
  63. return -1; //not found
  64. else if(value < node.value){
  65. System.out.println("Searching left");
  66. return search(value, node.left);
  67. }
  68. else if(value > node.value){
  69. System.out.println("Searching right");
  70. return search(value, node.right);
  71. }
  72. else
  73. return node.position;
  74. }
  75.  
  76. //二叉树DFS遍历
  77. public void travel(){
  78. travel(root);
  79. }
  80. public void travel(TreeNode node){
  81. if(node == null)
  82. return;
  83. travel(node.left);
  84. travel(node.right);
  85. System.out.println(" " + node.value);
  86. }
  87.  
  88. //二叉树的深度数
  89. public int depth(){
  90. return depth(root);
  91. }
  92.  
  93. private int depth(TreeNode node){
  94. if(node == null)
  95. return 0;
  96. int leftDepth = depth(node.left);
  97. int rightDepth = depth(node.right);
  98. return Math.max(leftDepth, rightDepth) + 1;
  99. }
  100.  
  101. public static void main(String[] args) {
  102. BinarySearchTree bst = new BinarySearchTree();
  103. int a[] = { 5, 8, 3, 4, 1, 7, 6};
  104. for(int i = 0; i < a.length; i++){
  105. bst.add(a[i], i);
  106. }
  107.  
  108. System.out.println("Tree Depth:" + bst.depth());
  109. }
  110.  
  111. }

其上面搜索二叉树再贴一下,以便可以直观的可以查看:

编译运行:

下面来debug看一下程序看如何计算出树的深度的:

a、将root = TreeNode(5, 0)传给带参数的depth方法进行递归遍历。

Loop1:其参数node = TreeNode(5, 0)

  b、,条件不满足,执行步骤c;

  c、,int leftDepth = depth(node.left = TreeNode(3, 2)),继续递归左结点:

    cb、,条件不满足,执行步骤cc;

    cc、,int leftDepth = depth(node.left = TreeNode(1, 4)),继续递归左结点:

      ccb、,条件不满足,执行步骤ccc;

      ccc、,int leftDepth = depth(node.left = null),继续递归左结点:

        cccb、,条件满足退出返回leftDepth = 0,执行步骤ccd;
      ccd、,int rightDepth = depth(node.right = null),继续递归右结点:

        cccb、,条件满足退出返回rightDepth = 0,执行步骤cce;

      cce、,result = 1; 

    所以这时leftDepth = 1;  

    cd、,int rightDepth = depth(node.right = TreeNode(4, 3)),继续递归右结点:

      cdb、,条件不满足,执行步骤cdc;

      cdc、,int leftDepth = depth(node.left = null),继续递归左结点:

        cdcb、,条件满足退出返回leftDepth = 0,执行步骤cdd;
      cdd、,int rightDepth = depth(node.right = null),继续递归右结点:

        cddb、,条件满足退出返回rightDepth = 0,执行步骤cde;

      cde、,result = 1; 
    所以这时leftDepth = 1;

    ce、,result = max(1, 1) + 1 = 2;

  所以这时leftDepth = 2;

  d、,int rightDepth = depth(node.right = TreeNode(8, 1)),继续递归右结点:

    db、,条件不满足,执行步骤dc;

    dc、,int leftDepth = depth(node.left = TreeNode(7, 5)),继续递归左结点:

      dcb、,条件不满足,执行步骤dcc;

      dcc、,int leftDepth = depth(node.left = TreeNode(6, 6)),继续递归左结点:

        dccb、,条件不满足,执行步骤dccc;

        dccc、,int leftDepth = depth(node.left = null),继续递归左结点:
          dcccb、,条件满足退出返回leftDepth = 0,执行步骤dccd;

        dccd、,int rightDepth = depth(node.right = null),继续递归右结点:

          dccdb、,条件满足退出返回rightDepth = 0,执行步骤dcce; 

        dcce、,result = max(0, 0) + 1 = 1;

      所以这时leftDepth = 1;  

      dcd、,int rightDepth = depth(node.right = null),继续递归右结点:

        dcdb、,条件满足退出返回rightDepth = 0,执行步骤dce;

      dce、,result = max(1, 0) + 1 = 2; 

    所以这时leftDepth = 2;

    dd、,int rightDepth = depth(node.right = null),继续递归右结点:

      ddb、,条件满足退出返回rightDepth = 0,执行步骤de;

    所以这时rightDepth = 0;

    de、,result = max(2, 0) + 1 = 3;

  所以这时rightDepth = 3;

  e、,result = max(2,3) + 1 = 4,所以最终此树的深度为4!

总结其实现思路:

1、递归的边界结束条件是传过来的节点为空了。

2、递归左结点的深度

3、递归右结点的深度

4、总结点的深度为左结点的深度+右结点的深度+1

上面已经实现了树的深度的计算,接下来则是利用DFS来将二叉树进行遍历啦,先上代码:

  1. public class BinarySearchTree {
  2. TreeNode root = null;
  3.  
  4. class TreeNode{
  5. int value;
  6. int position;
  7. TreeNode left = null, right = null;
  8. TreeNode(int value, int position){
  9. this.value = value;
  10. this.position = position;
  11. }
  12. }
  13.  
  14. public void add(int value, int position){
  15. if(root == null){//生成一个根结点
  16. root = new TreeNode(value, position);
  17. } else {
  18. //生成叶子结点
  19. add(value, position, root);
  20. }
  21. }
  22.  
  23. private void add(int value, int position, TreeNode node){
  24. if(node == null)
  25. throw new RuntimeException("treenode cannot be null");
  26. if(node.value == value)
  27. return; //ignore the duplicated value
  28. if(value < node.value){
  29. if(node.left == null){
  30. node.left = new TreeNode(value, position);
  31. }else{
  32. add(value, position, node.left);
  33. }
  34. }else{
  35. if(node.right == null){
  36. node.right = new TreeNode(value, position);
  37. }else{
  38. add(value, position, node.right);
  39. }
  40. }
  41. }
  42.  
  43. //打印构建的二叉搜索树
  44. static void printTreeNode(TreeNode node) {
  45. if(node == null)
  46. return;
  47. System.out.println("node:" + node.value);
  48. if(node.left != null) {
  49. printTreeNode(node.left);
  50. }
  51. if(node.right != null) {
  52. printTreeNode(node.right);
  53. }
  54. }
  55.  
  56. //搜索结点
  57. public int search(int value){
  58. return search(value, root);
  59. }
  60.  
  61. private int search(int value, TreeNode node){
  62. if(node == null)
  63. return -1; //not found
  64. else if(value < node.value){
  65. System.out.println("Searching left");
  66. return search(value, node.left);
  67. }
  68. else if(value > node.value){
  69. System.out.println("Searching right");
  70. return search(value, node.right);
  71. }
  72. else
  73. return node.position;
  74. }
  75.  
  76. //二叉树DFS遍历
  77. public void travel(){
  78. travel(root);
  79. }
  80. public void travel(TreeNode node){
  81. if(node == null)
  82. return;
  83. travel(node.left);
  84. travel(node.right);
  85. System.out.println(" " + node.value);
  86. }
  87.  
  88. //二叉树的深度数
  89. public int depth(){
  90. return depth(root);
  91. }
  92.  
  93. private int depth(TreeNode node){
  94. if(node == null)
  95. return 0;
  96. int leftDepth = depth(node.left);
  97. int rightDepth = depth(node.right);
  98. return Math.max(leftDepth, rightDepth) + 1;
  99. }
  100.  
  101. //二叉树的BFS遍历
  102. public void levelOrder(){
  103. int depth = depth();
  104. for(int level = 0; level < depth; level ++){
  105. printLevel(root, level);
  106. System.out.println("\n-------------------");
  107. }
  108. }
  109. private void printLevel(TreeNode node, int level){
  110. if(node == null)
  111. return;
  112. if(level == 0){
  113. System.out.print(" " + node.value);
  114. }else{
  115. printLevel(node.left, level - 1);
  116. printLevel(node.right, level - 1);
  117. }
  118. }
  119.  
  120. public static void main(String[] args) {
  121. BinarySearchTree bst = new BinarySearchTree();
  122. int a[] = { 5, 8, 3, 4, 1, 7, 6};
  123. for(int i = 0; i < a.length; i++){
  124. bst.add(a[i], i);
  125. }
  126.  
  127. System.out.println("Tree Depth:" + bst.depth());
  128. bst.levelOrder();
  129. }
  130.  
  131. }

编译运行:

下面再来debug一下其利用递归来BFS遍历的整个过程:

a、depth = 4

b、根据树的层次依次进行遍历打印,具体如下:

  Loop1:level = 0,level < 4条件为真,进入循环体:

    ①、递归打印第一层的所有结点:printLevel(root = TreeNode(5, 0), 0):

      c、判断node是否为null,条件为假,继续执行d;

      d、条件为真,直接打印"5"【level=0表示当前就是要打印的结点,因为每递归一次层会递减一,等到指定层也就减为0了】

    ②、打印一个分隔行以便结果可以看起来比较直观。"-------------------"

    level = level + 1 = 1;

  Loop2:level = 1,level < 4条件为真,进入循环体:

    ①、递归打印第一层的所有结点:printLevel(root = TreeNode(5, 0), 1):

      c、判断node是否为null,条件为假,继续执行d;

      d、条件为假,继续执行e;

      e、分别递归左右结点:

        ①、printLevel(node.left = TreeNode(3, 2), 0);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为真,直接打印"3";

        ②、printLevel(node.right = TreeNode(8, 1), 0);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为真,直接打印"8";

    ②、打印一个分隔行以便结果可以看起来比较直观。"-------------------"

    level = level + 1 = 2;

  Loop3:level = 2,level < 4条件为真,进入循环体:

    ①、递归打印第一层的所有结点:printLevel(root = TreeNode(5, 0), 2):

      c、判断node是否为null,条件为假,继续执行d;

      d、条件为假,继续执行e;

      e、分别递归左右结点:

        ①、printLevel(node.left = TreeNode(3, 2), 1);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为假,继续执行e;

          e、分别递归左右结点:
            ①、printLevel(node.left = TreeNode(1, 4), 0);   

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为真,直接打印"1";

            ②、printLevel(node.right = TreeNode(4, 3), 0);

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为真,直接打印"4";

        ②、printLevel(node.right = TreeNode(8, 1), 1);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为假,继续执行e;

          e、分别递归左右结点:
            ①、printLevel(node.left = TreeNode(7, 5), 0);   

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为真,直接打印"7";

            ②、printLevel(node.right = null);

              c、判断node是否为null,条件为真,直接返回递归结束。

    ②、打印一个分隔行以便结果可以看起来比较直观。"-------------------"

    level = level + 1 = 3;

  Loop4:level = 3,level < 4条件为真,进入循环体:

    ①、递归打印第一层的所有结点:printLevel(root = TreeNode(5, 0), 3):

      c、判断node是否为null,条件为假,继续执行d;

      d、条件为假,继续执行e;

      e、分别递归左右结点:

        ①、printLevel(node.left = TreeNode(3, 2), 2);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为假,继续执行e;

          e、分别递归左右结点:
            ①、printLevel(node.left = TreeNode(1, 4), 1);   

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为假,继续执行e;

              e、分别递归左右结点:

                ①、printLevel(node.left = null, 0);

                  c、判断node是否为null,条件为真,直接返回递归结束。

                ②、printLevel(node.right = null, 0);    

                  c、判断node是否为null,条件为真,直接返回递归结束。            

            ②、printLevel(node.right = TreeNode(4, 3), 1);

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为假,继续执行e;

              e、分别递归左右结点:

                ①、printLevel(node.left = null, 0);

                  c、判断node是否为null,条件为真,直接返回递归结束。

                ②、printLevel(node.right = null, 0);    

                  c、判断node是否为null,条件为真,直接返回递归结束。  

        ②、printLevel(node.right = TreeNode(8, 1), 2);

          c、判断node是否为null,条件为假,继续执行d;

          d、条件为假,继续执行e;

          e、分别递归左右结点:
            ①、printLevel(node.left = TreeNode(7, 5), 1);   

              c、判断node是否为null,条件为假,继续执行d;

              d、条件为假,继续执行e;

              e、分别递归左右结点:

                ①、printLevel(node.left = TreeNode(6, 6), 0);   

                  c、判断node是否为null,条件为假,继续执行d;

                  d、条件为真,直接打印"6";

                ②、printLevel(node.right = null);

                  c、判断node是否为null,条件为真,直接返回递归结束。

            ②、printLevel(node.right = null);

              c、判断node是否为null,条件为真,直接返回递归结束。

    ②、打印一个分隔行以便结果可以看起来比较直观。"-------------------"

    level = level + 1 = 4;

  Loop5:level = 4,level < 4条件为假,结束循环。

总结其实现思路:

1、首先获得树的层数,然后进行逐层打印。

2、每层打印时,都是从根节点开始来遍历的【很显示这种做法不是很高效,这节先学一种,未来会有更高效的做法】

3、在递归函数中有三个条件:

  a、如果当前节点是null,则直接返回递归结束。

  b、如果当前的层数为0,那证明就是要打印的层,则直接打印当前节点。

  c、以上两个条件都不满足,则说明该结点还有子结点,于是乎分别再次递归它的左结点和右结点,并且将层数减一。

下面来分析一下它的时间复杂度:

实际上整个算法是比较低效的,而上面的时间复杂度是O(n^2)级别的,未来会有更高效的O(n)线性级别的算法待学习,加油!

基于递归的BFS(Level-order)的更多相关文章

  1. (N叉树 BFS) leetcode429. N-ary Tree Level Order Traversal

    Given an n-ary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  2. [LeetCode] 103. Binary Tree Zigzag Level Order Traversal _ Medium tag: BFS

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  3. [LeetCode] 102. Binary Tree Level Order Traversal_Medium tag: BFS

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  4. leetcode 102 Binary Tree Level Order Traversal(DFS||BFS)

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  5. Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)

    Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...

  6. LeetCode :: Binary Tree Zigzag Level Order Traversal [tree, BFS]

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  7. 【LeetCode】Binary Tree Level Order Traversal 【BFS】

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  8. (二叉树 BFS) leetcode 107. Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  9. (二叉树 BFS) leetcode102. Binary Tree Level Order Traversal

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

随机推荐

  1. beSTORM之网络协议Fuzz入门教程

    转载自FreeBuf.COM 本文将以SNMP协议为例介绍如何使用beSTORM进行网络协议Fuzz. 实验环境 Windows 7 X64 (IP:192.168.0.123) beSTORM 3. ...

  2. 如何快速在Github找到你想要的东西

    众所周知 Github是全球最大的xx交友平台,虽然被收购了.但是不并没有什么影响. 使用Git可以做很多事,在这里不再缀述,上面的资源也是多种多样,应有尽有 对于这样一个平台,我们想快速找到自己需要 ...

  3. gx_dlms 的杂乱记录

    DLMS_ERROR_CODE_FALSE W3Jehpnc543MuwUz6ZWDshy5kwbbE9Cw CGXDLMSClient::GetData(CGXByteBuffer& rep ...

  4. nginx处理请求的11个阶段

    Nginx 处理请求的过程一共划分为 11 个阶段,按照执行顺序依次是 post-read.server-rewrite.find-config.rewrite.post-rewrite.preacc ...

  5. Spring mybatis源码篇章-动态SQL基础语法以及原理

    通过阅读源码对实现机制进行了解有利于陶冶情操,承接前文Spring mybatis源码篇章-Mybatis的XML文件加载 前话 前文通过Spring中配置mapperLocations属性来进行对m ...

  6. PTA(Advanced Level)1050.String Subtraction

    Given two strings S1 and S2, S=S1−S2 is defined to be the remaining string after taking all the char ...

  7. Vue ---- Vuex 的第一次接触

    在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用  props 或者 $emit 等方式 http://www.cnblogs.com/wisewrong/p/62660 ...

  8. Hello TypeScript

    ⒈TypeScript简介 1.JavaScript的超集 2.支持ECMAScript6标准,并支持输出ECMAScript3/5/6标准的纯JavaScript代码 3.支持ECMAScript未 ...

  9. 剑指offer17:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

    1 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 2 思路和方法 (1)先在A中找和B的根节点相同的结点 (2)找到之后遍历对应位置的其他结点, ...

  10. 【第一季】CH04_FPGA设计Verilog基础(一)Enter a post title

    [第一季]CH04_FPGA设计Verilog基础(一) 4.1 Verilog HDL 代码规范 u 项目构架设计 项目的构架用于团队的沟通,以及项目设计的全局把控 u 接口时序设计规范 模块和模块 ...