算法力扣刷题记录 五十八【701.二叉搜索树中的插入操作】

news2024/9/24 2:30:51

前言

本文是二叉搜索树操作。
二叉树篇继续。


一、题目阅读

给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。

注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。

示例 1:
在这里插入图片描述

	输入:root = [4,2,7,1,3], val = 5
	输出:[4,2,7,1,3,5]
	解释:另一个满足题目要求可以通过的树是:

示例 2:

	输入:root = [40,20,60,10,30,50,70], val = 25
	输出:[40,20,60,10,30,50,70,null,null,25]

示例 3:

	输入:root = [4,2,7,1,3,null,null,null,null,null,null], val = 5
	输出:[4,2,7,1,3,5]

提示:

树中的节点数将在 [0, 10^4]的范围内。
-10^8 <= Node.val <= 10^8
所有值 Node.val 是 独一无二 的。
-10^8 <= val <= 10^8
保证 val 在原始BST中不存在。

二、尝试解答

从示例一的图中可以看到,插入一个节点后仍然保持二叉搜索树,方式有很多种。

但是我想用递归实现,那么需要找到一个可以重复的操作。

思路

  1. 二叉搜索树中序遍历是有序递增的序列,那么插入节点要么插入到该序列最左端,成为新树的最小值;要么在序列中间插入;要么插入到序列的最右端,成为新树的最大值。
  2. 所以确定中序遍历。找到新节点的插入位置。
  3. 定一个遍历函数:中序递归操作——
  • 确定函数参数:TreeNode*& cur,int val。指针需要加引用,因为是对原树进行操作,如果不加引用,该层实现副本操作,返回上一层对原二叉树没有影响。
  • 确定函数返回值:void。因为用指针引用操作,所以直接修改树,不需要返回值。
  • 确定中间节点逻辑:
    • 如果cur->val中间节点值 > val插入的节点,那么:新建节点newnode——用temp接过原来的左子树——cur->left = newnode——newnode->left = temp。此流程可以保证是二叉搜索树注意,有问题:因为该逻辑在遍历右子树之前,所以后面递归到右子树,会重复插入很多这个新节点
    • 所以需要pre指针指向前一个节点。再加pre->val < val && cur->val > val。这才能正确插入一个新节点。
    • 还没有结束:上面是在序列中间插入;如果插入节点要么插入到该序列最左端呢?pre初始为空,且cur->val > val,说明插入到最左端。
    • 如果插入节点要么插入到该序列最右端呢?发现在递归函数中无法解决。只有在主函数里补充这个情况。pre全局变量最后一定指向原来二叉搜索树的最大值,那么在最大值->right = newnode。
  1. 再发现:如果原二叉树是空,在递归函数中也没有包含,仍然需要在主函数中涵盖。

代码实现

class Solution {
public:
    TreeNode* pre = nullptr;
    void insert(TreeNode*& cur,int val){//对树本身操作,所以树节点需要是引用形式
        if(!cur) return;
        insert(cur->left,val);
        if((pre &&pre->val < val && cur->val > val) || (!pre && cur->val > val) ){//确定了插入位置,数值在整个树中间或最左边
            TreeNode* newnode = new TreeNode(val);//新建节点
            TreeNode* temp = cur->left;//先断开下左子树,也包含空
            cur->left = newnode;//插入节点
            newnode->left = temp;
        }
        pre = cur;
        insert(cur->right,val);
        return;
    }
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(!root){//空树,补充。
            root = new TreeNode(val);
            return root;
        }
        insert(root,val);
        if(pre->val < val){//插入节点是最大的,补充最大值。
            TreeNode* newnode = new TreeNode(val);
            pre->right = newnode;
        }
        return root;
    }
};

所以,该思路按照插入节点在有序序列的位置,分3种情况;还有原树为空的情况。在递归函数中只能涵盖两种,剩下两种在主函数中补充。


三、参考学习

参考学习链接
有没有更统一的递归函数,改进上面的实现?

学习内容

  1. 思路插入节点后,新插入节点的位置都可以是叶子结点当前节点可以指明新插入节点的叶子位置。这个思路更简单。
    在这里插入图片描述

2.代码实现
虽然思路简单,但是代码实现上也需要注意——
(1)递归返回值给到上一层的左子树或右子树。遇到空,上一层节点左/右子树接住新建插入节点;
(2)插入之后,再向上层返回,返回的是root自身。

	class Solution {
	public:
	    TreeNode* insertIntoBST(TreeNode* root, int val) {
	        //终止条件,遇到空的时候,新建节点返回newnode
	        if(!root)  {
	            TreeNode* newnode = new TreeNode(val);
	            return newnode;
	        }
	        
	        if(root->val > val){
	            root->left = insertIntoBST(root->left,val);//用左子树接住空的返回值
	        }else if(root->val < val){
	            root->right = insertIntoBST(root->right,val);//需要用上一层的节点接住遇到空节点的新建节点
	        }
	
	        return root; 
	        
	    }
	};
  1. 递归不用返回值的函数
class Solution {
public:
    TreeNode* pre = nullptr;
    void traversal(TreeNode* cur,int val){
        if(!cur){
            TreeNode* node = new TreeNode(val);
            if(pre->val > val) pre->left = node;
            else pre->right = node;
            return;
        }
        pre = cur;
        if(cur->val > val){
            traversal(cur->left,val);
        }else if(cur->val < val){
            traversal(cur->right,val);
        }
        return;
    }
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(!root){
            root = new TreeNode(val);
            return root;
        }
        traversal(root,val);
        return root;
    }
};

对比参考代码:
(1)parent = new TreeNode(0);//没有。但是在root判空之后,新建节点,直接return。

  1. 迭代法,代码实现
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(!root){
            root = new TreeNode(val);
            return root;
        }
        TreeNode* cur = root;
        TreeNode* pre = nullptr;
        while(cur){
            pre = cur;
            if(cur->val > val){
                cur = cur->left;
            }else if(cur->val < val){
                cur = cur->right;
            }
        }
        //退出循环时,cur为空。pre是父节点
        TreeNode* node = new TreeNode(val);
        if(pre->val > val) pre->left = node;
        else pre->right = node;
        return root;
    }
};

对比参考代码:一样。


总结

【701.二叉搜索树中的插入操作】在这里插入图片描述
(欢迎指正,转载标明出处)

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

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

相关文章

【常见开源库的二次开发】基于openssl的加密与解密——SHA算法源码解析(六)

目录 一、SHA-1算法分析&#xff1a; 1.1 Merkle Tree可信树 1.2 源码实现&#xff1a; 1.3 哈希计算功能 1.4 两种算法的区别&#xff1a; 1.4.1 目的 1.4.2 实现机制 1.4.3 输出 1.4.4 应用场景&#xff1a; 1.4 运行演示&#xff1a; 二、SHA-2算法分析&#xff1a; 2.1哈…

【ESP32S3学习笔记】与有人AP520X路由器连接失败的问题

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 项目上新换了个路由器&#xff0c;结果发现ESP32模组连接不上&#xff0c;其他的路由器都正常。 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 对比log发现有问题的时候&#x…

智慧大棚数据库版

创建一个SMartBigHouse数据库 在数据库创建一个表用来存储数据 这边将id设为主键并将标识增量设为1 搭建Winfrom 搭建历史查询界面 串口数据&#xff0c;(这边是用的一个虚拟的串口工具&#xff0c;需要的话私) ModbusSerialMaster master;DataPointCollection wenduValues; //…

Win10使用VS Code远程连接Ubuntu服务器时遇到SSH公钥错误的解决方案

在使用Windows 10上的Visual Studio Code&#xff08;VS Code&#xff09;远程连接Ubuntu 20.04服务器时&#xff0c;遇到了以下错误&#xff1a; 错误的原因 这个错误消息表明&#xff0c;SSH 客户端检测到远程主机的 ECDSA 公钥已更改。可能是由于以下原因之一&#xff1a…

python—NumPy的基础(2)

文章目录 一维数组索引和切片一维数组索引和切片的使用一维数组负索引和切片的使用 二维数组的索引和切片索引直接获取使用坐标获取数组[x,y]二维数组负索引的使用切片数组的复制 改变数组的维度改变数组的维度 数组的拼接列表的拼接一维数组的拼接二维数组的拼接vstack 与hsta…

el-image预览图片点击遮盖处关闭预览

预览关闭按钮不明显 解决方式&#xff1a; 1.修改按钮样式明显点&#xff1a; //el-image 添加自定义类名&#xff0c;下文【test-image】代指 .test-image .el-icon-circle-close{ color:#fff; font-size:20px; ...改成很明显的样式 }2.使用事件监听&#xff0c;监听当前遮…

第十一章 数据结构

第十一章 数据结构 11.1 数组 数组是元素的顺序集合&#xff0c;通常这些元素具有相同的数据类型 索引表示元素在数组中的顺序号&#xff0c;顺序号从数组开始处计数 数组元素通过索引被独立给出了地址&#xff0c;数组整体上有一个名称&#xff0c;但每个元素利用数组的的…

TCP网络socket编程(面向连接)

Tcp面向链接、面向字节流和文件的读写非常类似&#xff08;&#xff09;&#xff1a;客户端创建套接字主动建立连接&#xff0c;服务器监听套接字一直等待连接的到来&#xff0c;监听到一个&#xff0c;就创建一个新的套接字用于IO 服务器&#xff1a; 创建套接字&#xff1a…

区块链和数据要素融合的价值及应用

一、数据要素面临的关键障碍 在构建数据要素基石的过程中&#xff0c;首要任务是明确并解决产权架构的难题&#xff0c;特别是使用权的确立与流转机制的顺畅&#xff0c;此乃数字经济蓬勃发展的命脉所在。一个高效的数据流转体系对于激发数据潜能、加速经济发展及优化数据资源…

TreeSelect增加可筛选功能

TreeSelect官方可筛选示例 <template><el-tree-selectv-model"value":data"data"filterablestyle"width: 240px"/><el-divider /><el-divider />filter node method:<el-tree-selectv-model"value":data&q…

使用torch_pruning对YOLOv8进行剪枝(新版、detect、segment)

torch_pruning库介绍 在结构修剪中&#xff0c;**Group被定义为深度网络中最小的可移除单元。**每个组由多个相互依赖的层组成&#xff0c;需要同时修剪这些层以保持最终结构的完整性。然而&#xff0c;深度网络通常表现出层与层之间错综复杂的依赖关系&#xff0c;这对结构修剪…

[大牛直播SDK]Windows平台RTMP直播推送模块功能设计

技术优势 全自研框架&#xff0c;易于扩展&#xff0c;自适应算法让延迟更低、采集编码传输效率更高&#xff1b;所有功能以SDK接口形式提供&#xff0c;所有状态&#xff0c;均有event回调&#xff0c;完美支持断网自动重连&#xff1b;SDK模块化&#xff0c;可和大牛直播播放…

DBeaver Ultimate 22.1.0 连接数据库(MySQL+Mongo+Clickhouse)

前言 继续书接上文 Docker Compose V2 安装常用数据库MySQL+Mongo,部署安装好之后我本来是找了一个web端的在线连接数据库的工具,但是使用过程中并不丝滑,最终还是选择了使用 DBeaver ,然后发现 mongo 还需要许可,又折腾整理了半下午,终于大功告成。 DBeaver 版本及说明…

SpringBoot集成Sharding-JDBC实现分库分表

本文已收录于专栏 《中间件合集》 目录 版本介绍背景介绍拆分方式集成并测试1.引入依赖2.创建库和表3.pom文件配置3.编写测试类Entity层Mapper接口MapperXML文件测试类 4.运行结果 自定义分片规则定义分片类编写pom文件 总结提升 版本介绍 SpringBoot的版本是&#xff1a; 2.3.…

SpringBoot上传超大文件导致Cannot read more than 2,147,483,647 into a byte array,问题解决办法

问题描述 报错: java.lang.IllegalArgumentException: Cannot read more than 2,147,483,647 into a byte array at org.apache.commons.io.IOUtils.lambda$toByteArray$0(IOUtils.java:2403) ~[commons-io-2.11.0.jar:2.11.0] at org.apache.commons.io.output.Thre…

python每日学习12:pandas库的用法(1)

python每日学习12&#xff1a;pandas库的用法&#xff08;1&#xff09; 安装 pip install pandas设定系统环境 import pandas as pd #设定自由列表输出最多为 10 行 pd.options.display.max_rows 10 # 显示当前 Pandas 版本号 pd.__version__进入jupyter notebook 页面 在终端…

氧气传感器在汽车制氧检测中的应用

在当今汽车工业中&#xff0c;技术的快速发展不仅带来了驾驶安全性和舒适性的显著提升&#xff0c;还为车辆增加了各种智能功能&#xff0c;以应对不同的驾驶环境和需求。氧气传感器作为一种关键的技术装置&#xff0c;在汽车制氧检测系统中的应用&#xff0c;尤其是针对疲劳驾…

困于数字化泥潭的软件公司|专题报告集

数字化专题报告集链接&#xff1a;https://tecdat.cn/?p36964 在探讨企业数字化转型的进程中&#xff0c;软件公司无疑扮演着举足轻重的角色。它们不仅是技术创新的驱动力&#xff0c;更是连接管理与技术的桥梁。然而&#xff0c;正如许多观察家所指出的那样&#xff0c;软件…

每天五分钟计算机视觉:目标检测模型从RCNN到Fast R-CNN的进化

本文重点 前面的课程中,我们学习了RCNN算法,但是RCNN算法有些慢,然后又有了基于RCNN的Fast-RCNN,Fast R-CNN是一种深度学习模型,主要用于目标检测任务,尤其在图像中物体的识别和定位方面表现出色。它是R-CNN系列算法的一个重要改进版本,旨在解决R-CNN中计算量大、速度慢…

jackson序列化(jackson codec)

Jackson 是一个用于 Java 平台的开源 JSON 库&#xff0c;它提供了灵活且高效的方式来处理 JSON 数据的序列化(Java对象 → JSON字符串)和反序列化(JSON 字符串→ Java对象)。 以下是 Jackson 的一些主要特点和功能&#xff1a; 高性能&#xff1a;Jackson 通过使用基于流的处理…