Day 25 二叉树的终止

450.删除二叉搜索树中的节点

不理解用tmp保存root节点,然后删除?root=root->right不会覆盖吗?

需要考虑要删除的节点是不是叶子节点,有无左右孩子

有左右孩子的话,需要将左孩子节点移动到右孩子节点的左面节点的左孩子上。

669. 修剪二叉搜索树

但是有返回值,更方便,可以通过递归函数的返回值来移除节点,大概解释下:

  1. 定义一个递归函数,它接受一个节点作为参数,并尝试在该节点及其子树中找到要移除的节点。
  2. 如果当前节点就是要移除的节点,返回该节点,并在适当的情况下更新其父节点的引用以跳过这个被移除的节点。
  3. 如果当前节点不是要移除的节点,递归地在左子树和右子树中查找并移除节点。
  4. 如果在左子树或右子树中找到了要移除的节点,更新当前节点的子节点引用以跳过被移除的节点。

迭代法是一种通过循环来重复执行某段代码直到满足某个条件为止的方法。在迭代过程中,通常使用循环结构(如whilefor循环)来控制代码的执行次数。迭代法不需要额外的函数调用栈空间,因为它直接在当前的函数栈帧中完成所有操作。

在剪枝二叉搜索树时,迭代法可以通过维护一个指针(如cur)来遍历树的节点,并根据需要更新指针的指向。这种方法不需要递归调用,因此可以避免额外的函数调用开销和栈空间使用。

1. 如果根节点为空,那么直接返回nullptr。 if (!root) return nullptr;
2. 移动根节点到[L, R]范围内:

while (root != nullptr && (root->val < L || root->val > R)) {  if (root->val < L) root = root->right; // 小于L往右走  else root = root->left; // 大于R往左走  
}


这段代码的目的是确保root节点位于[L, R]的范围内。如果root的值小于L,那么它会移动到root的右子树中;如果root的值大于R,那么它会移动到root的左子树中。
3. 处理左子树中小于L的节点:
TreeNode *cur = root;  
// 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况  

while (cur != nullptr) {  while (cur->left && cur->left->val < L) {  cur->left = cur->left->right;  }  cur = cur->left;  
}

从root开始,遍历左子树,并删除所有值小于L的节点。这是通过将其父节点的左指针指向其右子节点来实现的。
4. 重置cur并处理右子树中大于R的节点:

cur = root;  
// 此时root已经在[L, R] 范围内,处理右孩子大于R的情况  
while (cur != nullptr) {  while (cur->right && cur->right->val > R) {  cur->right = cur->right->left;  }  cur = cur->right;  
}

然后,再次从root开始,遍历右子树,并删除所有值大于R的节点。这是通过将其父节点的右指针指向其左子节点来实现的。
5. 返回修剪后的根节点:
return root;
最后,返回修剪后的树的根节点。

递归逻辑

  1. 如果root->val < low
    • 这种情况下,当前节点root及其左子树中的所有节点都应该被删除,因为它们都小于low
    • 我们递归地调用trimBST来处理root的右子树,并返回修剪后的右子树的根节点作为新的root
  2. 如果root->val > high
    • 这种情况下,当前节点root及其右子树中的所有节点都应该被删除,因为它们都大于high
    • 我们递归地调用trimBST来处理root的左子树,并返回修剪后的左子树的根节点作为新的root
  3. 如果low <= root->val <= high
    • 这种情况下,当前节点root的值在允许的范围内,所以我们需要保留它。
    • 我们递归地调用trimBST来处理root的左子树和右子树,并将修剪后的左子树的根节点赋值给root->left,将修剪后的右子树的根节点赋值给root->right
    • 最后返回root,因为它现在是修剪后的子树的根节点。

关键点

  • 由于BST的特性(父节点的值大于左子树中所有节点的值,小于右子树中所有节点的值),我们可以直接根据当前节点的值与lowhigh的比较结果来决定是否保留该节点以及是否继续递归处理其子树。
  • 递归是处理树形结构的有效方法,它可以将复杂的问题分解为更小的子问题来解决。在这个问题中,递归地修剪左子树和右子树是保持BST性质的关键。
  • 函数的返回值是修剪后的子树的根节点,这允许我们在递归调用中构建并返回修剪后的树。

108.将有序数组转换为二叉搜索树

核心在于利用了二叉搜索树(BST)的特性以及二分查找(Binary Search)的思想来迭代地将一个有序数组转化为一个BST。

首先,让我们分析这段代码:

  1. traversal 函数是一个私有辅助函数,它接受一个有序数组 nums、一个左索引 left 和一个右索引 right 作为参数。这三个参数定义了一个子数组的范围,该函数的任务是根据这个子数组的范围来构建BST的一个子树。

  2. 如果 left > right,说明子数组为空(或只有一个元素但已经被前面的递归处理了),那么返回 nullptr,表示没有节点需要创建。

  3. 否则,找到子数组的中间元素 mid,这个元素将成为当前BST子树的根节点。这利用了BST的特性:根节点的值总是大于左子树的所有值,小于右子树的所有值。

  4. 递归地调用 traversal 函数来构建左子树(使用 left 到 mid - 1 的索引范围)和右子树(使用 mid + 1 到 right 的索引范围)。这是二分查找的关键步骤,它将原始问题(构建整个BST)分解为两个更小的问题(构建左子树和右子树)。

  5. 最后,将左子树和右子树连接到根节点,并返回根节点。

  6. sortedArrayToBST 函数是公开的,它接受一个有序数组 nums 并调用 traversal 函数来构建BST的根节点。这个根节点是整个BST的入口点。

class Solution {
private:TreeNode* traversal(vector<int>& nums, int left, int right) {if (left > right) return nullptr;int mid = left + ((right - left) / 2);TreeNode* root = new TreeNode(nums[mid]);root->left = traversal(nums, left, mid - 1);root->right = traversal(nums, mid + 1, right);return root;}
public:TreeNode* sortedArrayToBST(vector<int>& nums) {TreeNode* root = traversal(nums, 0, nums.size() - 1);return root;}
};

538.把二叉搜索树转换为累加树

将二叉搜索树(BST)转换为一个累加树(Greater Sum Tree),其中每个节点的新值是该节点原始值及其所有后续节点(在中序遍历中的顺序)原始值的和。由于BST的特性(左子节点值小于父节点,右子节点值大于父节点),我们可以通过反中序遍历(右-根-左)来实现这个转换。

在反中序遍历中,我们从BST的最大值开始(即最右边的节点),然后向上遍历到根节点,并继续向左遍历,这样我们就能确保在遍历到每个节点时,我们已经计算出了所有后续节点的和。

1. 不需要递归函数的返回值做什么操作了,要遍历整棵树。

2. 遇空就终止。

3. 于当前访问的节点cur,我们将其值更新为cur.val + pre.val(如果pre是节点)或cur.val + pre(如果pre是整数值)。然后,我们更新pre为当前节点cur(如果pre是节点)或cur.val(如果pre是整数值)。

class Solution {  
private:  // 私有成员变量pre,用于记录前一个节点的累加值(初始化为0)  int pre = 0; // 记录前一个节点的数值  // 定义一个私有函数traversal,用于执行反中序遍历(右-根-左)并更新节点值  void traversal(TreeNode* cur) { // 右中左遍历  // 如果当前节点为空,则返回(结束递归)  if (cur == NULL) return;  // 先遍历右子树  traversal(cur->right);  // 更新当前节点的值为原值加上前一个节点的累加值  cur->val += pre;  // 更新pre为当前节点的值(包括累加值),以便后续节点使用  pre = cur->val;  // 再遍历左子树  traversal(cur->left);  }  public:  // 公开成员函数convertBST,接收一个二叉搜索树的根节点作为参数  // 执行反中序遍历并更新节点值,然后返回根节点(此时根节点已经是累加树的根节点)  TreeNode* convertBST(TreeNode* root) {  // 初始化pre为0  pre = 0;  // 执行反中序遍历并更新节点值  traversal(root);  // 返回转换后的累加树的根节点  return root;  }  
};

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

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

相关文章

了解常用智能指针

智能指针 1、概念 C中引入智能指针的主要目的是为了解决内存管理的问题&#xff0c;传统的指针&#xff08;裸指针&#xff09;在使用时需要手动分配和释放内存&#xff0c;容易出现内存泄漏和悬挂指针等问题。智能指针通过封装裸指针&#xff0c;并提供自动内存管理功能&…

一、Socket创建和连接

C网络编程&#xff08;asio&#xff09; 文章目录 C网络编程&#xff08;asio&#xff09;1、Asio概述2、网络编程基本流程2、创建socket3、创建监听socket4、绑定accpet监听套接字5、连接指定的端点6、服务器接收连接 点击查看代码 1、Asio概述 ​ Asio起源于Boost库&#xf…

shell编程(三)—— 运算符

和其他编程语言一样&#xff0c;bash也有多种类型的运算符&#xff0c;本篇对bash的相关运算符做简单介绍。 一、运算符 1.1 算术运算符 常见的算术运算符&#xff0c;如加&#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xf…

OpenGauss数据库-4.表的创建、修改与删除

第1关&#xff1a;创建表 gsql -d postgres -U gaussdb -W passwd123123 create database testdb; \c testdb; passwd123123 create table test_table (test_id integer not null,test_info char(36)); 第2关&#xff1a;修改表 gsql -d testsb -U gaussdb -W passwd123123 …

YOLOv5的predict.py逐句讲解(学习笔记)

因为太多依赖python的各种库,导致自己对YOLO的开发能力有所下降,最近准备重新整理一下YOLO系列的代码以供以后自己查阅。 YOLOv5-v7.0将分类脱离出来了。predict.py为分类的推理代码。predict.py主要有run(),parse_opt(),main()三个函数构成。 一、导入模块 这部分导入pyth…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 机场航班调度程序(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 🌍 评测功能需要订阅专栏后私信联系清隆解锁~ 文章目录 …

Flink 基于 TDMQ Apache Pulsar 的离线场景使用实践

背景 Apache Flink 是一个开源的流处理和批处理框架&#xff0c;具有高吞吐量、低延迟的流式引擎&#xff0c;支持事件时间处理和状态管理&#xff0c;以及确保在机器故障时的容错性和一次性语义。Flink 的核心是一个分布式流数据处理引擎&#xff0c;支持 Java、Scala、Pytho…

DeepSORT(目标跟踪算法)中的马氏距离详解(很详细)

DeepSORT&#xff08;目标跟踪算法&#xff09;中的马氏距离详解&#xff08;很详细&#xff09; flyfish 马氏距离的公式是由印度统计学家【普拉萨纳钱德拉马哈拉诺比斯&#xff08;Prasanta Chandra Mahalanobis&#xff09;】&#xff09;&#xff08;好长的名字&#xff…

怎样快速获取Vmware VCP 证书,线上考试,voucher报名优惠

之前考一个VCP证书&#xff0c;要花大一万的费用&#xff0c;可贵了&#xff0c;考试费不贵&#xff0c;贵就贵在培训费&#xff0c;要拿到证书&#xff0c;必须交培训费&#xff0c;即使vmware你玩的很溜&#xff0c;不需要再培训了&#xff0c;但是一笔贵到肉疼的培训费你得拿…

哈希表与哈希扩容

一&#xff0c;哈希表 哈希表简单的理解&#xff1a;在记录的存储位置和它的关键字之间建立一个确定的对应关系f&#xff0c;使每个关键字和结构中一个唯一的存储位置相对应。 哈希表基于数组的&#xff0c;正因为数组创建后难于扩展某些哈希表被基本填满时&#xff0c;性能下…

JS类型转换面试题:[] == ![] 为true?

前言 OK,又是在学习的路上遇到了难点&#xff0c;今天拿来分享一哈。ok&#xff0c;话不多说&#xff0c;开始分享。 下面是一道面试题 console.log([]![])你觉得上面的值打印为多少&#xff1f;我告诉你&#xff0c;打印的结果是true。如果你是猜对的或者不会可以看看我对这…

Python从入门到精通的学习路径

Python从入门到精通的学习路径 基础语法&#xff1a; 学习Python的基本语法&#xff0c;包括变量、数据类型、运算符、流程控制&#xff08;如if、else、for、while&#xff09;等。参考书籍或在线教程&#xff0c;如《Python从入门到精通》系列教程&#xff0c;特别是“Pytho…

JVM学习笔记02

三十九、运行时数据区内部数据

Capture One 23 软件安装教程、附安装包下载

Capture One Capture One 23 是一款功能极为全面的图片处理软件&#xff0c;为用户提供了真正的逼真色彩处理和无缝衔接的编辑体验&#xff0c;以及业界最快的联机拍摄功能&#xff0c;可以满足用户在图像创作上的所有功能&#xff0c;如创作全景拼接大图、高级色彩调整、遮罩…

0605-JavaSE-单例模式-饿懒汉模式

​​​​​​​ 不能放在方法里面&#xff08;因为每个线程调用都会在方法里面实例化一个locker对象&#xff0c;但不属于同一个对象&#xff09;&#xff0c;然后要用static修饰成静态变量才会起到效果 //单例设计模式 //饿汉模式&#xff1a;在加载类的时候就已经开始创建 /…

Python项目开发实战:智能停车场车牌识别计费系统(案例教程)

开发一个智能停车场车牌识别计费系统是一个综合了多个技术领域(如图像处理、数据库管理、Web开发等)的项目。 一、项目概述 1.项目目标: 实现车牌识别功能。 设计并实现计费逻辑。 构建用户友好的前端界面。 实现后台管理系统。 2.技术栈: 后端:Python(Django/Flask等…

Opencv基本操作

Opencv基本操作 导入并使用opencv进行图像与视频的基本处理 opencv读取的格式是BGR import cv2 #opencv读取的格式是BGR import numpy import matplotlib.pyplot as plt %matplotlib inline图像读取 通过cv2.imread()来加载指定位置的图像信息。 img cv2.imread(./res/ca…

3-哈希表-51-四数相加 II-LeetCode454

3-哈希表-51-四数相加 II-LeetCode454 LeetCode: 题目序号454 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&#xff…

定时TH1、计数TL1 的计算

定时器模式 通常在模式 1 下&#xff0c;定时器 1 是 16 位定时器&#xff08;2的16次方65536&#xff09;&#xff08;8位256&#xff09;。定时器的计时周期是由 TH1 和 TL1 的组合值决定的。初始值为 65536 − ( T H 1 256 T L 1 ) 65536 - (TH1 \times 256 TL1) 65536…

Spring boot注解学习

1、SpringBootApplication spring boot 核心注解&#xff0c;加在Spring boot 主类之上&#xff0c;是Configuration、EnableAutoConfiguration、ComponentScan 注解的集合。  &#xff08;1&#xff09;Configuration&#xff1a;允许以Bean注解将对象托管给spring容器&#…