树-广度优先和深度优先搜索算法

2023-10-27

广度优先和深度优先搜索算法

本章主要讲述广度优先搜索算法BFS(Breadth First Search)和深度优先算法DFS(Depth First Search)。

  1. 广度优先:从起点开始由近及远进行广泛搜索,一般使用队列实现
  2. 深度优先:从起点开始沿着一条路径一直往下,直到不能搜索为止,再折返沿着另一条路径往下搜索,使用或者递归实现

在这里插入图片描述
下面将以上图中的树来举例实现搜索,每个节点的数据结构如下

public static class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

广度优先搜索

  1. 从根节点开始遍历,将根节点加入队列,队列为[50]
  2. 将队首节点50的所有子节点按照从左到右的顺序加入队列,队列为[50,3,67]
  3. 将节点50移出队列,队列为[3,67]
  4. 重复步骤2、3直到所有节点遍历完毕,即可完成广度优先搜索

遍历结果:50, 3, 67, 1, 34, 55, 13, 23

java代码实现如下

    /**
     * 广度优先搜索
     * @param root
     * @return
     */
    public int[] bfs(TreeNode root) {
        if (root == null) {
            return new int[0];
        }
        List<Integer> result = new LinkedList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root); /* 将根节点放入队列 */
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll(); /* 取出队首节点node */
            result.add(node.val);
            if (node.left != null) {
                queue.add(node.left); /* 将node的左节点加入队列 */
            }
            if (node.right != null) {
                queue.add(node.right); /* 将node的右节点加入队列 */
            }
        }
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

深度优先搜索

根据节点的遍历顺序,深度优先搜索分为先序遍历中序遍历后序遍历

  1. 先序遍历:先输出当前节点,再遍历左节点,最后遍历右节点。遍历左、右节点时,依然按照先序遍历的规则遍历。
  2. 中序遍历:先遍历左节点,再输出当前节点,最后遍历右节点。遍历左、右节点时,依然按照中序遍历的规则遍历。
  3. 后序遍历:先遍历左节点,再遍历右节点,最后输出当前节点。遍历左、右节点时,依然按照后续遍历的规则遍历。

先序遍历

输出结果:50, 3, 1, 34, 13, 23, 67, 55

    /**
     * 深度优先搜索-先序遍历,递归实现
     *
     * @param root
     * @return
     */
    public int[] dfsPreorder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        dfsPreorder(root, result);
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

    public void dfsPreorder(TreeNode node, List<Integer> result) {
        if (node == null) {
            return;
        }
        result.add(node.val); // 输出当前节点
        dfsPreorder(node.left, result); // 遍历左节点
        dfsPreorder(node.right, result); // 遍历右节点
    }

先序遍历栈实现思路:

  1. 先序遍历顺序为:输出当前节点 → 遍历左节点 → 遍历右节点
  2. 可以从根节点开始,优先遍历左子树,最后再遍历右子树,将所有节点按照遍历顺序输出即可得到先序遍历结果
    /**
     * 深度优先搜索-先序遍历,栈实现
     *
     * @param root
     * @return
     */
    public int[] dfsPreorder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node); 
                result.add(node.val); // 输出当前节点
                node = node.left; // 向左遍历
            } else {
                node = stack.pop();
                node = node.right; // 向右遍历
            }
        }
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

中序遍历

输出结果:1, 3, 13, 23, 34, 50, 55, 67

    /**
     * 深度优先搜索-中序遍历,递归实现
     *
     * @param root
     * @return
     */
    public int[] dfsMidOrder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        dfsMidOrder(root, result);
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

    public void dfsMidOrder(TreeNode node, List<Integer> result) {
        if (node == null) {
            return;
        }
        dfsMidOrder(node.left, result); // 遍历左节点
        result.add(node.val); // 输出当前节点
        dfsMidOrder(node.right, result); // 遍历右节点
    }

中序遍历栈实现思路:

  1. 中序遍历顺序为: 遍历左节点 → 输出当前节点 → 遍历右节点
  2. 从根节点开始,优先遍历左子树,最后再遍历右子树,将所有节点按照出栈输出即可得到先序遍历结果

注意:中序遍历要求左节点优先输出,所以节点入栈时不要输出,待节点出栈再输出

    /**
     * 深度优先搜索-中序遍历,栈实现
     *
     * @param root
     * @return
     */
    public int[] dfsMidOrder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node); // 当前节点入栈
                node = node.left; // 向左遍历
            } else {
                node = stack.pop(); // 栈顶元素没有左节点,此时向右遍历
                result.add(node.val);
                node = node.right; // 向右遍历
            }
        }
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

后序遍历

输出结果:1, 23, 13, 34, 3, 55, 67, 50

    /**
     * 深度优先搜索-后序遍历,递归实现
     *
     * @param root
     * @return
     */
    public int[] dfsPostorder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        dfsPostorder(root, result);
        return result.stream().mapToInt(Integer::intValue).toArray();
    }

    public void dfsPostorder(TreeNode node, List<Integer> result) {
        if (node == null) {
            return;
        }
        dfsPostorder(node.left, result); // 遍历左节点
        dfsPostorder(node.right, result); // 遍历右节点
        result.add(node.val); // 输出当前节点
    }

后序遍历栈实现思路:

  1. 后序遍历顺序为:遍历左节点 → 遍历右节点 → 输出当前节点
  2. 按照栈先进后出的特点,入栈顺序应为:当前节点 → 右节点 → 左节点
  3. 可以从根节点开始,优先遍历右子树,最后再遍历左子树,将所有节点按照遍历顺序保存到栈中,最后按顺序出栈即可得到后序遍历结果
    /**
     * 深度优先搜索-后续遍历,栈实现
     *
     * @param root
     * @return
     */
    public int[] dfsPostorder(TreeNode root) {
        List<Integer> result = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;

        while (node != null || !stack.isEmpty()) {
            if (node != null) {
                stack.push(node); // 入栈顺序是后序遍历的倒叙排列
                result.add(0, node.val); // 将倒叙变为正序
                node = node.right; // 向右遍历
            } else {
                node = stack.pop().left; // 向左遍历
            }

        }
        return result.stream().mapToInt(Integer::intValue).toArray();
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

树-广度优先和深度优先搜索算法 的相关文章

  • python利用图像处理方法 实现多目标检测与裁剪(opencv)

    图像处理方法实现多目标检测与裁剪 简述 1 批量resize 1 效果 2 原理 3 代码分析 2 找出所有目标轮廓 定位 1 效果 2 原理 3 代码分析 3 确定裁剪区域 1 效果 2 原理 3 代码分析 源代码 简述 对于一些特殊多目
  • HTTP1、HTTP2、HTTPS详解

    HTTP1 HTTP 协议老的标准是HTTP 1 0 为了提高系统的效率 HTTP 1 0规定浏览器与服务器只保持短暂的连接 浏览器的每次请求都需要与服务器建立一个TCP连接 服务器完成请求处理后立即断开TCP连接 服务器不跟踪每个客户也不
  • 软件外包接单经验谈-需求篇

    上一篇谈了如何寻找客户 这一期就谈谈在和客户接洽时 如何与客户沟通需求 在这里我不去套用类似PMP里面那些完善的高大上的需求管理的方法论 因为我第一篇文章就说了 我写的这一系列文章都是针对小公司或者个人承接的外包项目 也就是都是一些中小项目
  • Android dumpsys使用

    目录 一 dumpsys命令介绍 1 命令介绍 2 服务查询和介绍 二 核心服务信息查询 1 package包信息查询 2 activity信息查询 3 window信息查询 三 实现自定义服务dumpsys信息查询 一 dumpsys命令

随机推荐

  • NodeJS - 回调函数

    什么是回调函数 回调函数是一个异步等价的函数 在给定任务完成时调用回调函数 NodeJS大量使用回调 NodeJS的所有API都是以支持回调的方式编写的 例如 读取文件的函数可能会开始读取文件后并立即将控件返回到执行环境 以便可以执行下一条
  • 区块链-区块链特点

    目录 https blog csdn net qq 40452317 article details 89646633 区块链 Blockchain 是一系列现有成熟技术的有机组合 它对账本进行分布式的有效记录 并且提供完善的脚本以支持不同
  • Qt 2D图形平面绘制

    Qt 2D图形平面绘制 一 图形视图框架 Graphics View Framework 二 实战 1 步骤 2 代码 三 参考 四 总结 一 图形视图框架 Graphics View Framework QGraphicsScene 场景
  • RocketMQ解析

    文章目录 1 单机版消息中心 2 分布式消息中心 2 1 问题与解决 2 1 1 消息丢失的问题 2 1 2 同步落盘怎么才能快 2 1 3 消息堆积的问题 2 1 4 定时消息的实现 2 1 5 顺序消息的实现 2 1 6 分布式消息的实
  • 软件测试进阶篇

    测试专栏 软件测试的基本概念 关于软件测试 作为一个测试人员 这些基础知识必不可少 关于测试用例 目录 一 按照测试对象来划分 1 界面 2 可靠性的测试 3 容错性 4 文档测试 5 兼容性测试 6 易用性测试 7 安装卸载测试 8 安全
  • Java string的基本用法

    Java string的基本用法 一 定义字符串与子串 定义 String e 空字符串 String E Hello 提取子串使用Substring方法 String E Hello String s E substring 0 4 s等
  • 《数字化转型》——企业持续有效增长的新引擎

    中国国民经济和社会发展第十四个五年规划和2035念远景目标纲要 明确指出 迎接数字时代 激活数据要素潜能 推动网络强国建设 加快建设数字经济 数字社会 数字政府 以数字化转型整体驱动生产方式 生活方式和治理方式变革 那么企业如何做 如何选型
  • Nginx通过/etc/init.d/nginx方式启动或停止服务

    Linux Nginx启动 停止 重启脚本 Nginx 启动 重启 停止脚本 第一步 先运行命令关闭nginx sudo kill cat usr local nginx logs nginx pid lt
  • Python时间序列预测大气二氧化碳浓度

    二氧化碳 CO2 和甲烷 CH4 等温室气体 GHG 会在大气中捕获热量 从而使我们的星球保持温暖 对生物物种友好 无论如何 燃烧化石燃料等人类活动会导致大量温室气体排放 从而过度提高地球的全球平均温度 因此 向可持续的全球经济转型势在必行
  • 极光笔记

    01 营销人 你是否饱受困扰 作为营销人的你 从996到007 每天从早忙到晚 但还是没办法把访客转化成客户 作为营销人的你 想通过APP通知 短信 邮件 公众号消息等方式 把所有能想到的营销方式 万箭齐发 结果却收效甚微 作为营销人的你
  • unity 设置animation不循环

    Unity中动画创建后 将会生成一个后缀名为 anim的文件 里面包含着动画内容 里面有一个属性 叫Loop Time 创建时它默认是勾选的 如果想去掉 可先找到你生成动画时创建的 anim文件 点击它 在右边Inspector栏里面找到L
  • MediaCodec、OpenGL、OpenSL/AudioTrack 实现一款简单的视频播放器

    概述 功能很简单 大致流程为 1 MediaCodec 解码视频文件得到 YUV PCM 数据 2 OpenGL 将 YUV 转为 RGB 并渲染到 Surface 上 3 OpenSL AudoTrack 获取 PCM 数据并播放 需要的
  • IDEA插件ASM Bytecode Outline

    IDEA插件ASM Bytecode Outline
  • Python之map()函数详解

    文章目录 一 map 函数简介 1 1 map 函数基本语法 1 2 map 函数 lambda表达式 1 3 map 函数输入多个可迭代对象iterable 1 4 查看返回的迭代器内容 二 map 函数示例 示例一 使用 map 函数操
  • CentOS 7.6镜像下载

    目前在国内使用最多的两个Linux发行版本一个是CentOS 另外一个是Ubuntu CentOS是一个可以重新分发的开源操作系统 也是企业Linux发行版的领头羊 官方目前发布的最新CentOS版本为CentOS 9 那么如何到下载旧版本
  • 一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3

    1 题目描述 一个数组有 N 个元素 求连续子数组的最大和 例如 1 2 1 和最大的连续子数组为 2 1 其和为 3 输入描述 输入为两行 第一行一个整数n 1 lt n lt 100000 表示一共有n个元素 第二行为n个数 即每个元素
  • 从利用Arthas排查线上Fastjson问题到Java动态字节码技术(中)

    上一篇文章 中通过对一次线上事故的复盘 引出了福报厂的Arthas 一个建立在Java动态字节码技术之上的Java诊断工具 关于Arthas的使用方式就不赘述了 查看官方文档可以很快上手 玩法也特别多 上一篇中也仅仅只介绍了一种使用场景 即
  • c++ 建立链表并实现合并

    创建两个链表并实现两个链表相加 include
  • 《大型网站技术架构》序

    推荐序一 1 传统企业应用于大型网站应用的区别 传统的企业应用系统主要面对的技术挑战是处理复杂凌乱 干变万化的所谓业务逻辑 而大型网站主要面对的技术挑战是处理超大量的用户访问和海量的数据处理 前者的挑战来自功能性需求 后者的挑战来自非功能性
  • 树-广度优先和深度优先搜索算法

    广度优先和深度优先搜索算法 本章主要讲述广度优先搜索算法BFS Breadth First Search 和深度优先算法DFS Depth First Search 广度优先 从起点开始由近及远进行广泛搜索 一般使用队列实现 深度优先 从起