前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >BFS(广度优先算法)也就这么回事

BFS(广度优先算法)也就这么回事

作者头像
写代码的阿宗
发布2020-08-24 11:15:48
5660
发布2020-08-24 11:15:48
举报

最近在刷关于树的题,其实树也是面试中面试官喜欢考察的问题。对树稍微有了解的同学想必都知道解决这类问题无非是遍历,BFS(广度优先)或者是DFS(深度优先)。这俩其实都不难理解,顾名思义,优先从那边搜索,依次遍历。今天我们来谈谈BFS,DFS留到下次再说。

一个树的结构大概是这样的:

二叉树

广度优先算法的核心是按层级依次遍历一个树,对于如上这个树来讲,我们遍历的顺序就是12->7->1->9->10->5。那么怎样才能按照这个顺序遍历整棵树呢,同一个层级的各个节点看起来没什么关联。后期我们就得想办法让它们产生这样的顺序了。

我们先来看一道题目:给定一个二叉树,填充一个数组来代表它的层级关系。把每个层级从左到右填充进一个独立的子数组,返回最后的数组

拿到手,发现题目很直接地向我们表达了层级关系,用广度优先没跑了。而且我们也不需要做些额外的操作,单纯地遍历一遍就好了。

我们得先解决让同一层级的节点按顺序处理的问题。我们可以发现,同一层级的节点顺序是由上一层的节点决定的,那我们在处理上一层节点的时候,就已经能知道下一层子节点的顺序了。那其实只需要用某种数据结构把子节点按照顺序存起来就好了,我们就用Queue这个数据结构吧(其实其它数据结构也都可以,只不过队列适合保存一些按顺序处理用完就丢的东西,而且数据数量一直在变化,会有频繁的放入取出操作,所以相比于List还是Queue更方便)。通过Queue我们可以很方便地对树进行广度优先搜索。我们大概会有如下几个步骤:

  1. 向Queue中放入root节点。
  2. 只要这个Queue中有元素就一直遍历。
  3. 每次遍历时,首先计算一下当前Queue里有多少个元素,这就是这棵树当前层级元素的数量,记作levelSize。
  4. 接下来从Queue中移除levelSize这么多个元素,对他们进行符合我们题目的一些操作。
  5. 移除每个节点时,把它们的子节点添加进Queue中。
  6. 只要Queue中还有元素,说明还有下一个层级,就一直重复步骤3去处理下一个层级。

整个过程就这么多,是不是看起来很简单?但是往往就是这简单的搜索,好多人就是实现不出来。

按照上面分析的步骤,我们来实现以下这个算法:

public static List<List<Integer>> traverse(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (root == null)
            return result;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            List<Integer> currentLevel = new ArrayList<>(levelSize);
            for (int i = 0; i < levelSize; i++) {
                TreeNode currentNode = queue.poll();
                currentLevel.add(currentNode.val);
                // 把子节点插入到队列中
                if (currentNode.left != null)
                    queue.offer(currentNode.left);
                if (currentNode.right != null)
                    queue.offer(currentNode.right);
            }
            result.add(currentLevel);
        }

        return result;
    }

只消事先获取到当前层级的数量来控制好循环,再把子节点添加到队列中,整个流程就算是完成了,之后想对每个子元素或者每个层级做什么操作都可以。后面要是让大家逆序啊,S形啊来表示树的结构都很简单了。

通过上面的讨论,想必大家都对BFS有个感性的认识了。接下来,我们再来看一个变形题,来进一步加深对广度优先搜索的印象。

是这样的:给定一个二叉树,把每个层级上的节点跟它在这个层级上的后面一个节点连接起来,每个层级的最后一个节点要指向null

这道题跟上面那个题其实一个路子,那我们也按照相同的套路来解题就行咯。还是用广度优先算法,唯一的不同就是,在遍历一个层级的时候,我们要记住前一个结点,以使它跟后面一个节点相连。其余的过程还是跟之前一样一样的。

public static void connect(TreeNode root) {
        if (root == null)
            return;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode previousNode = null;
            int levelSize = queue.size();
            //连接当前层及所有的点
            for (int i = 0; i < levelSize; i++) {
                TreeNode currentNode = queue.poll();
                if (previousNode != null)
                    previousNode.next = currentNode;
                previousNode = currentNode;

                // 把当前节点的子节点插入队列
                if (currentNode.left != null)
                    queue.offer(currentNode.left);
                if (currentNode.right != null)
                    queue.offer(currentNode.right);
            }
        }
    }

看吧,万变不离其宗,换汤不换药,我们只要掌握了基本题目的解题步骤,再遇到这些变形题时,只要一开始发现了题目的意图,总能按照我们的思路一步一步把算法写出来。而所谓的广度优先算法,在现在看来也就这么回事儿,一般一般。

好了,关于BFS今天就写到这里了,大家平时也可以自己去刷一些类型的题目总结出自己的规律跟套路,形成自己对题目的意识,在网上每天都有新的题目被提出来,掌握核心才能让自己效率最大化。Happy coding~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 写代码的阿宗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档