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

数据结构——二叉树练习

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

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

路径之和

在这里插入图片描述

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);}// 遍历结束后,队列中剩余的节点应全为空,因为它们对应于完全二叉树中不存在的节点// 如果队列中还有非空节点,说明这不是完全二叉树,返回falsewhile (!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.hqwc.cn/news/651929.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

净初级生产力NPP数据

生态系统是地球上生命存在的舞台&#xff0c;而生态系统的能量来源之一是净初级生产力&#xff08;NPP&#xff09;。NPP是生态系统中植物通过光合作用将太阳能转化为有机物质的速率&#xff0c;是生态系统中生物量增长和能量积累的重要指标之一。 NPP的重要性 NPP反映了生态系…

python的turtle库画直线

1.画一条直线 让画笔从(0,0)划到&#xff08;100,100&#xff09;&#xff0c;在turtle中画笔是一只小乌龟。 import turtle turtle.setup(800,800,0,0)#turtle.setup(width,height,startx,starty)来设置窗口初始位置及大小 turtle.goto(100,100)2.画一条折线 left和right使小…

【UE5.1 C++】提升编译速度

步骤 1. 在“C:\Users\用户\AppData\Roaming\Unreal Engine\UnrealBuildTool”目录下找到“BuildConfiguration.xml”文件 打开“BuildConfiguration.xml”&#xff0c;添加如下部分内容 <?xml version"1.0" encoding"utf-8" ?> <Configuratio…

TypeScript入门第一天,所有类型+基础用法+接口使用

表示逻辑值&#xff1a;true 和 false。在JavaScript和TypeScript里叫做boolean | | 数组类型 | 无 | 声明变量为数组。 // 在元素类型后面加上[] let arr: number[] [1, 2]; // 或者使用数组泛型&#xff0c;Array<元素类型> let arr: Array [1, 2]; | | 元组…

vue与Spring boot数据交互例子【简单版】

文章目录 什么是Vue&#xff1f;快速体验Vueaxios是什么&#xff1f;向Springboot后端发送数据接收Springboot后端数据小结 什么是Vue&#xff1f; 官网解释&#xff1a;Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上…

济宁市中考报名照片要求及手机拍照采集证件照方法

随着中考报名季的到来&#xff0c;并且进入了中考报名演练阶段&#xff0c;济宁市的广大考生和家长都开始忙碌起来。报名过程中&#xff0c;上传一张符合要求的证件照是必不可少的环节。本文将详细介绍济宁市中考报名照片的具体要求&#xff0c;并提供一些实用的手机拍照采集证…

php反序列化字符串逃逸

字符串逃逸 字符串逃逸是通过改变序列化字符串的长度造成的php反序列化漏洞 一般是因为替换函数使得字符串长度发生变化&#xff0c;不论变长还是变短&#xff0c;原理都大致相同 在学习之前&#xff0c;要先了解序列化字符串的结构&#xff0c;在了解结构的基础上才能更好理解…

ubuntu22 部署fastDFS单节点和集群,整合Spring Boot(刚部署成功)

ubuntu22 部署fastDFS单节点和集群 一、先准备1、所需依赖安装2、下载安装包 二、安装FastDFS单节点1、libfastcommon安装1.1、创建软连接 2、安装fastDFS2.1、fastDFS目录简单介绍2.2、创建软连接 3、配置和启动Tracker服务3.1、修改Tracker配置文件3.2、启动Tracker 4、配置和…

DS进阶:并查集

一、并查集的原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这…

配置opencv属性表

编译opencv cmake -DCMAKE_INSTALL_PREFIX./install -G "Visual Studio 15 2017" -A x64 .. cmake -DCMAKE_INSTALL_PREFIX./install -G "Visual Studio 15 2017" -A Win32 ..cmake --build . --config Release -j 2cmake --build . --config Release --t…

滴水逆向 FileBuffer-ImageBuffer 课后作业

1)- 实现如下功能 #include<stdio.h> #include<stdlib.h> #include<windows.h> BYTE* bufferApply nullptr;//将磁盘文件复制到内存中后, 使用bufferApply指向该空间 DWORD fileSize 0;//将磁盘文件复制到内存时使用需要申请空间, 使用fileSize设置申请空…

Netty 应用与原理

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 Java IO 模型 本篇示例代码仓库&#xff1a;learn-netty 基础概念 在 I/O 操作中有这么两组概念&#xff0c;其中同步/异步 要和线程中的同步线程/异步线程要区分开&#xff0c;这里指的是同步IO / 异步IO…