数据结构——二叉树练习(深搜广搜)

news2025/1/18 8:14:51

数据结构——二叉树练习

  • 路径之和
  • 深度优先算法和广度优先算法
  • 二叉搜索树
  • 判断一棵二叉树是否为搜索二叉树和完全二叉树

我们今天来看二叉树的习题:

路径之和

在这里插入图片描述

https://leetcode.cn/problems/path-sum-ii/

这是一个典型的回溯,深度优先算法的题,这里我们来简单的介绍一下深度优先算法和广度优先算法:

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

深度优先搜索(Depth-First Search, DFS)和广度优先搜索(Breadth-First Search, BFS)是两种常用的图(或树)遍历算法。虽然它们都是用于探索图中所有节点的策略,但在搜索顺序和所需数据结构上有所不同。

深度优先搜索(DFS)

深度优先搜索是一种沿着图的深度方向尽可能深地搜索的算法。它会优先访问离起点最近的未访问节点的子节点,直到到达叶子节点(没有子节点的节点)或无法继续深入为止,然后回溯到上一个节点,尝试访问其未被访问的另一个子节点,重复这一过程,直到图中所有节点都被访问过。

实现方式

  • 递归实现:从某个起始节点开始,递归地访问其未访问过的子节点。
  • 栈实现:使用栈来保存待访问节点,每次从栈顶取出一个节点,访问它,并将其未访问过的子节点压入栈中。

广度优先搜索(BFS)

广度优先搜索是一种从起点开始,按层次逐层向外遍历的算法。它会先访问与起点距离最近的所有节点(即邻居节点),然后再访问这些节点的邻居节点,以此类推,直到遍历到目标节点或遍历完整个图。

实现方式

  • 队列实现:使用队列来保存待访问节点,每次从队头取出一个节点,访问它,并将其未访问过的邻居节点加入队尾。

比较

  • 搜索顺序

    • DFS:沿着一条路径深入到底,再回溯并尝试另一条路径,类似“纵深”探索。
    • BFS:从起点开始,逐层向外扩散,类似于“地毯式”搜索。
  • 所需数据结构

    • DFS:递归实现时不需要额外数据结构;栈实现时需用到栈。
    • BFS:需要使用队列。
  • 空间复杂度

    • DFS:递归实现的空间复杂度取决于递归调用的深度,最坏情况下可能达到O(n);栈实现的空间复杂度为O(n),n为图中节点数。
    • BFS:空间复杂度为O(n),需要存储所有待访问节点。
  • 适用场景

    • DFS:适用于寻找图中是否存在某条路径、求解最短路径问题(无权图)等,特别是在高度大于宽度的图中效果较好。
    • BFS:适用于求解最短路径问题(有权图需使用Dijkstra算法或A*算法等)、寻找两个节点间的最短路径、拓扑排序等问题,特别是在宽度大于高度的图中效果较好。

我们今天这道题就是一个深度优先搜索,我们拿这棵树来举例子:
在这里插入图片描述
我们用二维vector来存放满足条件的路径:
在这里插入图片描述
我们从3开始,先往左走,到9:
在这里插入图片描述
3 + 9 = 12故将3和9放入vector[0]中:
在这里插入图片描述
这个时候,往回走,回到3:
在这里插入图片描述回到3,便往右走:
在这里插入图片描述
重复上述步骤,整理思路可得代码:

class Solution {
public:
	// 定义一个成员函数 dfs,用于实现深度优先搜索,查找所有和为目标值的路径
	void dfs(TreeNode* root, vector<int>& path, vector<vector<int>>& result,
	         int targetSum)
	{
	    // 如果当前节点为空,直接返回
	    if (root == nullptr)
	    {
	        return;
	    }
	
	    // 将当前节点的值加入路径,并从目标和中减去该值
	    path.push_back(root->val);
	    targetSum -= root->val;
	
	    // 如果当前节点是叶子节点(无左右子节点),且剩余目标和为0,说明找到了一条符合条件的路径
	    if (root->left == nullptr && root->right == nullptr && targetSum == 0)
	    {
	        result.push_back(path); // 将当前路径加入结果集
	    }
	
	    // 递归遍历左子树
	    dfs(root->left, path, result, targetSum);
	
	    // 递归遍历右子树
	    dfs(root->right, path, result, targetSum);
	
	    // 回溯:从路径中移除当前节点的值,以便于后续节点的搜索
	    path.pop_back();
	}
	
	// 定义一个成员函数 pathSum,用于查找二叉树中所有和为目标值的路径
	vector<vector<int>> pathSum(TreeNode* root, int targetSum)
	{
	    // 初始化结果容器,用于存放所有和为目标值的路径
	    vector<vector<int>> result;
	
	    // 初始化当前路径向量
	    vector<int> path; // 当前路径
	
	    // 调用 dfs 函数,从根节点开始搜索
	    dfs(root, path, result, targetSum);
	
	    // 返回找到的所有和为目标值的路径
	    return result;
	}
};

二叉搜索树

二叉搜索树(Binary Search Tree, BST)是一种特殊类型的二叉树,它具有以下关键属性:

定义与性质:

有序性:对于二叉搜索树中的任意节点,其左子树中所有节点的值都严格小于该节点的值,而右子树中所有节点的值都严格大于该节点的值。这保证了树中的数据按照某种顺序排列。
递归结构:二叉搜索树的每个子节点(如果存在)本身也是一个二叉搜索树,也就是说,整个数据结构具有递归性质。

我们之前自己实现的二叉树就是二叉搜索树,如果还有小伙伴不怎么熟悉的,可以点击这里:

https://blog.csdn.net/qq_67693066/article/details/138163494

有一个重要的性质:二叉树的中序遍历是一个递增的数列,这个用来判断搜索二叉树是一个非常关键的方法。

判断一棵二叉树是否为搜索二叉树和完全二叉树

在这里插入图片描述

https://www.nowcoder.com/practice/f31fc6d3caf24e7f8b4deb5cd9b5fa97?tpId=196&tqId=37156&ru=/exam/oj

我们可以利用二叉搜索树中序遍历的特点来判断是否为二叉搜索树,判断是否为完全二叉树,这里我们就可以借助队列,用广度优先搜索

假设我们有一棵完全二叉树:
在这里插入图片描述

如果利用队列,全部放在队列中,应该是这样的顺序:
在这里插入图片描述

如果是非完全二叉树:
在这里插入图片描述
我们发现,如果是完全二叉树,那么空节点应该全都集中在末尾,如果是非完全二叉树,中间就会出现空结点所以我们只要在遇到空结点时,检查之后是否有结点,如果没有就是完全二叉树,有的话就是非完全二叉树

// 定义一个成员函数 judgeCompelte,用于判断给定的二叉树是否为完全二叉树
bool judgeCompelte(TreeNode* root)
{
    // 初始化一个队列,用于按层遍历二叉树
    queue<TreeNode*> queue;

    // 如果根节点不为空,将其入队
    if (root)
        queue.push(root);

    // 使用队列进行层序遍历
    while (!queue.empty())
    {
        // 弹出队首节点
        TreeNode* front = queue.front();
        queue.pop();

        // 如果遇到空节点,表示已经到达当前层的最后一个有效节点,跳出循环
        if (front == nullptr)
            break;

        // 将当前节点的左右子节点(无论是否为空)依次入队,准备遍历下一层
        queue.push(front->left);
        queue.push(front->right);
    }

    // 遍历结束后,队列中剩余的节点应全为空,因为它们对应于完全二叉树中不存在的节点
    // 如果队列中还有非空节点,说明这不是完全二叉树,返回false
    while (!queue.empty())
    {
        TreeNode* front = queue.front();
        queue.pop();

        if (front)
        {
            return false;
        }
    }

    // 队列已清空,且所有弹出的节点都符合完全二叉树的条件,返回true,表示给定二叉树是完全二叉树
    return true;
}

判断是否为二叉搜索树:

// 中序遍历二叉树,并将遍历结果存储在给定的向量中
void inorder(TreeNode* root, vector<int>& vc) {
    if (root == nullptr) {
        return;
    }

    inorder(root->left, vc); // 遍历左子树
    vc.push_back(root->val); // 将当前节点的值添加到向量中
    inorder(root->right, vc); // 遍历右子树
}

// 判断给定的二叉树是否为二叉搜索树
bool isBST(TreeNode* root) {
    vector<int> vc;
    inorder(root, vc); // 对二叉树进行中序遍历

    for (int i = 0; i < vc.size() - 1; i++) {
        if (vc[i] >= vc[i + 1]) { // 如果当前元素大于或等于下一个元素,则不是二叉搜索树
            return false;
        }
    }

    return true; // 如果所有元素都小于下一个元素,则是二叉搜索树
}

那么这道题就可以迎刃而解了:

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    //判断完全是否为完全二叉树
    bool judgeCompelte(TreeNode* root)
    {
        //初始化队列
        queue<TreeNode*> queue;

        //入队
        if(root)
            queue.push(root);

    
        while(!queue.empty())
        {
            TreeNode* front = queue.front();
            queue.pop();

            if(front == nullptr)
                break;
            
            queue.push(front->left);
            queue.push(front->right);
            
        }

        while(!queue.empty())
        {
           TreeNode* front = queue.front();
           queue.pop();

            if (front)
            {
                return false;
            }
        }

        return true;
    }

    //中序遍历
    void inoder(TreeNode* root,vector<int>& vc)
    {
        if(root == nullptr)
        {
            return;
        }

        inoder(root->left,vc);
        vc.push_back(root->val);
        inoder(root->right,vc);
    }

    
    //判断
    vector<bool> judgeIt(TreeNode* root) 
    {
       vector<bool> result(2,false); 
       if(!root)
       {
            result[0] = true;
            result[1] = true;
            return result;
       }

       //判断是否为二叉搜索树
       vector<int> vc;
       inoder(root,vc);
       result[0] = true;

       for(int i = 0; i <vc.size() - 1; i++)
       {
            if(vc[i] >= vc[i+1])
            {
                result[0] = false;
                break;
            }
       }

       //判断是否为完全二叉树
      result[1] = judgeCompelte(root);

       return result; 
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1628113.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker镜像和容器操作

目录 一.Docker镜像创建与操作 1. 搜索镜像 2. 获取镜像 3. 镜像加速下载 4. 查看镜像信息 5. 查看下载的镜像文件信息 ​编辑6. 查看下载到本地的所有镜像 7. 根据镜像的唯一标识ID号&#xff0c;获取镜像详细信息 8. 为本地的镜像添加新的标签 9. 删除镜像 10. 存入…

【1731】jsp 房租跟踪监控管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 房租跟踪监控管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

【uniapp/ucharts】采用 uniapp 框架的 h5 应用使用 ucharts(没有 uni_modules)

这种情况无法直接从 dcloud 平台上一键下载导入&#xff0c;所以应该在官网推荐的 git 仓库去单独下载&#xff1a; https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6/qiun-data-charts(%E9%9D%9Euni_modules) 下载的文件是如图所示的路径&…

AI大模型探索之路-训练篇2:大语言模型预训练基础认知

文章目录 前言一、预训练流程分析二、预训练两大挑战三、预训练网络通信四、预训练数据并行五、预训练模型并行六、预训练3D并行七、预训练代码示例总结 前言 在人工智能的宏伟蓝图中&#xff0c;大语言模型&#xff08;LLM&#xff09;的预训练是构筑智慧之塔的基石。预训练过…

如何将web content项目导入idea并部署到tomcat

将Web Content项目导入IntelliJ IDEA并部署到Tomcat主要涉及以下几个步骤&#xff1a; 1. 导入Web Content项目 打开IntelliJ IDEA。选择“File” -> “New” -> “Project from Existing Sources…”。浏览到你的Web Content项目的文件夹&#xff0c;并选择它。Intell…

数据结构(C):时间复杂度和空间复杂度

目录 &#x1f680; 0.前言 &#x1f680; 1.为何会有时间复杂度和空间复杂度的概念 &#x1f680; 2.时间复杂度 2.1初步时间复杂度 2.2大O表示法 2.2.1.O&#xff08;N*N&#xff09; 2.2.2.O&#xff08;N&#xff09; 2.2.3.O&#xff08;1&#xff09; 2.3最坏情况…

【Qt】error LNK2001: 无法解析的外部符号

参考&#xff1a;Qt/VS LNK2019/LNK2001&#xff1a;无法解析的外部符号_qt lnk2001无法解析的外部符号-CSDN博客 微软官方报错文档-链接器工具错误 LNK2019 __declspec error LNK2001: 无法解析的外部符号 "__declspec(dllimport) 原因 以这种为前缀的基本上跟库相关…

微信小程序:11.本地生活小程序制作

开发工具&#xff1a; 微信开发者工具apifox进行创先Mock 项目初始化 新建小程序项目输入ID选择不使用云开发&#xff0c;js传统模版在project.private.config中setting配置项中配置checkinalidKey&#xff1a;false 梳理项目结构 因为该项目有三个tabbar所以我们要创建三…

点击消除

点击消除 描述&#xff1a; 对一个字符串&#xff0c;每次“点击”&#xff0c;可以把字符串中相邻两个 相同字母消除。 例如&#xff0c;字符串"abbc"点击后可以生成"ac"。 但相同而不相邻、不相同的相邻字母都是不可以被消除的。 如果想把字符串变得…

比亚迪24届春招Offer面经

本文介绍2024届春招中&#xff0c;比亚迪的高级底盘工程师岗位1场面试的基本情况、提问问题等。 2024年04月投递了比亚迪的系统开发类、 技术研发类、 技术研究类岗位&#xff0c;面试结束后分配至高级底盘工程师岗位&#xff1b;面试前未确定部门&#xff0c;面试结束后分配至…

关于OSPF报文学习

目录 一.OSPF学习补充 &#xff08;1&#xff09;OSPF报文头部 &#xff08;2&#xff09;ospf建立邻居关系 1.Hello报文——建立邻居关系 2.hello报文头部 &#xff08;3&#xff09;OSPF建立邻接关系 1.发送DD报文 2.DD报文头部 &#xff08;4&#xff09;关于DR,BD…

Blender点操作

顶点操作即一般的“布线”操作 1.顶点移动 -先切到顶点模式 -移动&#xff0c;G 或 G X/Y/Z -旋转&#xff0c;R 同上 -缩放&#xff0c;S 同上 2.顶点滑移&#xff0c;用于微调顶点的位置 快捷键&#xff1a;Shift V&#xff0c;G G 3.顶点删除 -选中一个顶点 -按…

【算法】人工蜂群算法,解决多目标车间调度问题,柔性车间调度问题

文章目录 复现论文什么是柔性作业车间调度问题&#xff1f;数据处理ABC算法编码解码种群初始化雇佣蜂操作IPOX交叉多点交叉 观察蜂操作侦察蜂操作算法流程 结果程序截图问询、帮助 复现论文 什么是柔性作业车间调度问题&#xff1f; 也叫多目标车间调度问题。 柔性作业车间调…

构建NodeJS库--前端项目的打包发布

1. 前言 学习如何打包发布前端项目&#xff0c;需要学习以下相关知识&#xff1a; package.json 如何初始化配置&#xff0c;以及学习npm配置项&#xff1b; 模块类型type配置&#xff0c; 这是nodejs的package.json的配置main 入口文件的配置 webpack 是一个用于现代 JavaSc…

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法&#xff0c;调用接头体的方法&#xff0c;获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型(type)、类别(kind)如果是结构体变量&#xff0c;…

Java应用开发必备:使用 easy-captcha 组件生成验证码的详细介绍

一、前言 最近系统开发在优化验证码的相关功能&#xff0c;第一反应就是有没有开源的第三方组件可以使用呢。 在一番寻觅以后&#xff0c;还真发现一个好用的第三方验证码组件Easy-captcha。Easy-captcha是一个开源的Java库&#xff0c;用于生成和验证验证码&#xff0c;它的…

RGB灯珠的控制-单片机通用模板

RGB灯珠的控制-单片机通用模板 一、RGB控制的原理二、RGB.c的实现三、RGB.h的实现四、color色彩空间变换以及控制渐变一、RGB控制的原理 ①通过IO发送脉冲识别0/1编码,组合24Bit的RGB数据,从而控制RGB;②每个RGB灯珠通过DIN、DOU进行级联起来;③通过HSV色彩转换成RGB从而控…

Tomcat架构设计精髓分析-Connector高内聚低耦合设计

优秀的模块化设计通常都会采用高内聚、低耦合 高内聚是指相关度比较高的功能要尽可能集中&#xff0c;不要分散。低耦合是指两个相关的模块要尽可能减少依赖的部分和降低依赖的程序&#xff0c;不要让两个模块产中强依赖。 Tomca连接器需要实现的功能: 监听网络端口 接受网络…

手撕netty源码(一)- NioEventLoopGroup

文章目录 前言一、NIO 与 netty二、NioEventLoopGroup 对象的创建过程2.1 创建流程图2.2 EventExecutorChooser 的创建 前言 processOn文档跳转 本文是手撕netty源码系列的开篇文章&#xff0c;会先介绍一下netty对NIO关键代码的封装位置&#xff0c;主要介绍 NioEventLoopGro…

使用PyCharm开发工具创建工程

一. 简介 前面文章实现了开发 python程序使用的 开发工具PyCharm&#xff0c;本文来学习使用 PyCharm开发工具创建一个 python工程。 二. 使用PyCharm开发工具创建工程 1. 首先&#xff0c;打开 PyCharm开发工具&#xff0c;打开 "New project" 选项&#xff1a; …