二叉搜索树(BST)的创建及增,删,查,改(详解)

目录

初识二叉搜索树(BST):

二叉搜索树查找元素:

二叉搜索树修改元素:

二叉搜索树中的增加元素:

二叉搜索树中的删除元素:


初识二叉搜索树(BST):

一张图简要概括二叉搜索树:

通过定义可知,对于每个节点,左子树的所有节点的值都比它小,右子树的所有节点值都比它大,我们可以很轻易的得出这颗树的最左侧叶子节点的值是最小值,最右侧叶子节点的值是最大值。

那中序遍历为什么一定是有序的呢?原理也很简单, 我们先看看二叉树递归的图解:

 对于图中的二叉树,中序遍历的结果是:3,2,4,1,7,6,5。按照左子树-》根-》右子树的模式不断递归,结合BST左小右大的特性,那么先得到的值一定是当前树中最小的,同时根是次小的,最后是当前树中最大的。从底部出发,向上不断回溯调用,就得到了顺序的结果。

二叉搜索树查找元素:

题目链接:700. 二叉搜索树中的搜索 - 力扣(LeetCode)

题目描述:

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

如果是在一颗不同的二叉树中搜索(代码如下):

TreeNode searchBST(TreeNode root, int target);
    if (root == null) return null;
    if (root.val == target) return root;
    // 当前节点没找到就递归地去左右子树寻找
    TreeNode left = searchBST(root.left, target);
    TreeNode right = searchBST(root.right, target);

    return left != null ? left : right;//相当于返回叶子节点
}

其实不需要递归地搜索两边,类似二分查找思想,根据 target 和 root.val 的大小比较,就能排除一边。我们把上面的思路稍稍改动:

TreeNode searchBST(TreeNode root, int target) {
    if (root == null) {
        return null;
    }
    // 去左子树搜索
    if (root.val > target) {
        return searchBST(root.left, target);
    }
    // 去右子树搜索
    if (root.val < target) {
        return searchBST(root.right, target);
    }
    return root;//上面两个都不满足,说明root.val == target直接返回root
}

二叉搜索树修改元素:

无非就是先找到元素对应的位置后再修改该位置对应的值:

TreeNode searchBST(TreeNode root, int target,num) {
    if (root == null) {
        return null;
    }
    // 去左子树搜索
    if (root.val > target) {
        return searchBST(root.left, target);
    }
    // 去右子树搜索
    if (root.val < target) {
        return searchBST(root.right, target);
    }
    root.val = num;//将树中对应的target值改为num
    return root;//上面两个都不满足,说明root.val == target直接返回root
}

二叉搜索树中的增加元素:

这里我们需要更改二叉搜索树的结构:一旦涉及「改」,就类似二叉树的构造问题,函数要返回 TreeNode 类型,并且要对递归调用的返回值进行接收

TreeNode insertIntoBST(TreeNode root, int val) {
    // 找到空位置插入新节点
    if (root == null) return new TreeNode(val);//这里就相当于将节点接入到二叉树对应的叶子中
    // if (root.val == val)
    //     BST 中一般不会插入已存在元素
    if (root.val < val) 
        root.right = insertIntoBST(root.right, val);
    if (root.val > val) 
        root.left = insertIntoBST(root.left, val);
    return root;
}

二叉搜索树中的删除元素:

这个问题稍微复杂,跟插入操作类似,先「找」再「改」,先把框架写出来再说:

TreeNode deleteNode(TreeNode root, int key) {
    if (root.val == key) {
        // 找到啦,进行删除
    } else if (root.val > key) {
        // 去左子树找
        root.left = deleteNode(root.left, key);
    } else if (root.val < key) {
        // 去右子树找
        root.right = deleteNode(root.right, key);
    }
    return root;
}

找到目标节点了,比方说是节点 A,如何删除这个节点,这是难点。因为删除节点的同时不能破坏 BST 的性质。有三种情况,用图片来说明。

情况 1A 恰好是末端节点,两个子节点都为空,那么它可以当场去世了。

if (root.left == null && root.right == null)
    return null;

 情况 2A 只有一个非空子节点,那么它要让这个孩子接替自己的位置。

// 排除了情况 1 之后
if (root.left == null) return root.right;
if (root.right == null) return root.left;

 情况 3A 有两个子节点,麻烦了,为了不破坏 BST 的性质,A 必须找到左子树中最大的那个节点,或者右子树中最小的那个节点来接替自己。我们以第二种方式讲解。

if (root.left != null && root.right != null) {
    // 找到右子树的最小节点
    TreeNode minNode = getMin(root.right);
    // 把 root 改成 minNode
    root.val = minNode.val;
    // 转而去删除 minNode
    root.right = deleteNode(root.right, minNode.val);
}

三中情况都完成后,整理一下代码:

TreeNode deleteNode(TreeNode root, int key) {
    if (root == null) return null;
    if (root.val == key) {
        // 这两个 if 把情况 1 和 2 都正确处理了
        if (root.left == null) return root.right;
        if (root.right == null) return root.left;
        // 处理情况 3
        // 获得右子树最小的节点
        TreeNode minNode = getMin(root.right);
        // 删除右子树最小的节点
        root.right = deleteNode(root.right, minNode.val);
        // 用右子树最小的节点替换 root 节点
        minNode.left = root.left;
        minNode.right = root.right;
        root = minNode;
    } else if (root.val > key) {
        root.left = deleteNode(root.left, key);
    } else if (root.val < key) {
        root.right = deleteNode(root.right, key);
    }
    return root;
}

TreeNode getMin(TreeNode node) {
    // BST 最左边的就是最小的
    while (node.left != null) node = node.left;
    return node;
}

参考:《labuladong算法笔记》

结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固自己的知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虚幻4 | 制作游戏——学习记录(一)

1. 启动Epic后下载虚幻4&#xff0c;打开虚幻4后新建一个第三人称游戏项目&#xff0c;效果如下&#xff1a; &#xff08;1&#xff09;内容/ThirdPersonBP/Blueprints中的ThirdPersonCharacter&#xff08;左下角人物&#xff09; 这是模板中使用的主要蓝图类&#xff0c;它…

LED驱动控制芯片SM5166:可消除LED显示模组毛毛虫现象

SM5166是一款LED驱动控制芯片&#xff0c;专为LED显示模组设计&#xff0c;具备多项先进功能。以下是关于SM5166的详细解释&#xff1a; 1. 消除LED显示模组毛毛虫现象&#xff1a;毛毛虫现象是LED显示屏上一种常见的显示问题&#xff0c;表现为在显示动态图像时&#xff0c;L…

LVS (Linux Virtual server)集群介绍

一 集群和分布式 &#xff08;一&#xff09;系统性能扩展方式&#xff1a; Scale UP&#xff1a;垂直扩展&#xff0c;向上扩展,增强&#xff0c;性能更强的计算机运行同样的服务 &#xff08;即升级单机的硬件设备&#xff09; Scale Out&#xff1a;水平扩展&#xff0…

TomCat9的安装与配置

什么是TomCat Tomcat,作为Apache软件基金会下的一个开源项目,是广泛使用的Java Servlet容器和Web服务器。Tomcat提供了运行Java Web应用程序的环境,并且由于其对Servlet和JSP的支持,它成为了许多Java Web应用程序的首选服务器。下面,我们将详细介绍Tomcat的安装与配置过程…

Codeforces Round 932(Div.2) A~E

A.Entertainment in MAC&#xff08;字符串&#xff09; 题意&#xff1a; 恭喜你&#xff0c;你被硕士援助中心录取了&#xff01;但是&#xff0c;你在课堂上感到非常无聊&#xff0c;于是你给自己想了一个游戏。 给你一个字符串 s s s和一个偶数整数 n n n。你可以对它进…

软件测试技术分享 | 测试环境搭建

被测系统的环境搭建&#xff0c;是我们作为软件测试人员需要掌握的技能。 被测系统AUT (Application Under Test) 常见的被测系统即需要被测试的 app&#xff0c;网页和后端服务。大致分为两个方面移动端测试和服务端测试&#xff0c;如下图所示&#xff1a; 常见的被测系统类…

javaSE-----继承和多态

目录 一.初识继承&#xff1a; 1.1什么是继承&#xff0c;为什么需要继承&#xff1a; 1.2继承的概念与语法&#xff1a; 二.成员的访问&#xff1a; 2.1super关键字 2.2this和super的区别&#xff1a; 三.再谈初始化: 小结&#xff1a; 四.初识多态&#xff1a; 4.1多…

RabbitMQ架构详解

文章目录 概述架构详解核心组件虚拟主机&#xff08;Virtual Host&#xff09;RabbitMQ 有几种广播类型 概述 RabbitMQ是⼀个高可用的消息中间件&#xff0c;支持多种协议和集群扩展。并且支持消息持久化和镜像队列&#xff0c;适用于对消息可靠性较高的场合 官网https://www.…

ubuntu22.01安装及配置

前言 本次安装基于VMware Pro 16进行安装。 ubuntu版本&#xff1a;ubuntu-22.04.3-live-server-amd64.iso 1、下载 1.1官网下载 https://ubuntu.com/download 1.2、清华大学镜像网站下载 https://mirrors.tuna.tsinghua.edu.cn/ 进入网站后搜索ubuntu&#xff0c;选择ubu…

谷粒商城【成神路】-【10】——缓存

目录 &#x1f9c2;1.引入缓存的优势 &#x1f953;2.哪些数据适合放入缓存 &#x1f32d;3.使用redis作为缓存组件 &#x1f37f;4.redis存在的问题 &#x1f9c8;5.添加本地锁 &#x1f95e;6.添加分布式锁 &#x1f95a;7.整合redisson作为分布式锁 &#x1f697…

uniapp封装文字提示气泡框toolTip组件

uniapp封装文字提示气泡框toolTip组件 文字提示气泡框&#xff1a;toolTip 因为uniapp 中小程序中没有window对象&#xff0c;需手动调用 关闭 第一种办法关闭&#xff1a;this.$refs.tooltip.close() 第二种办法关闭&#xff1a;visible.sync false 移动端没有现成的toolTip组…

pytorch项目代码记录

目录 1.超过二维的张量写进csv 2.翻转矩阵与绘制热力图 3.切片 4.np按块复制 1.超过二维的张量写进csv #(20,204,273) -> (4080,273) ycsv []for i in range(20):ycsv.append(y[i, 8, :, :].reshape(204,273))with open(y.csv,w,encodingutf-8) as y_obj:writer csv.…

SpringCloud 服务的注册与发现

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第二篇&#xff0c;即使用服务注册和发现的组件&#xff0c;此篇文章会介绍 Eureka、Zookeeper 和 Consu…

C++初阶 类(上)

目录 1. 什么是类 2. 如何定义出一个类 3. 类的访问限定符 4. 类的作用域 5. 类的实例化 6. 类的大小 7. this指针 1.this指针的引出 2. this指针的特性 8. 面试题 1. 什么是类 在C语言中&#xff0c;不同类型的数据集合体是结构体。为了方便管理结构体&#xff0c;我…

CVHub | 万字长文带你全面解读视觉大模型(建议收藏!)

本文来源公众号“CVHub”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;万字长文带你全面解读视觉大模型 0 导读 众所周知&#xff0c;视觉系统对于理解和推理视觉场景的组成特性至关重要。这个领域的挑战在于对象之间的复杂关系…

centos7 python3.12.1 报错 No module named _ssl

https://blog.csdn.net/Amio_/article/details/126716818 安装python cd /usr/local/src wget https://www.python.org/ftp/python/3.12.1/Python-3.12.1.tgz tar -zxvf Python-3.12.1.tgz cd Python-3.12.1/ ./configure -C --enable-shared --with-openssl/usr/local/opens…

Docker镜像及Dockerfile详解

1 Docker镜像用途 统一应用发布的标准格式支撑一个Docker容器的运行 2 Docker镜像的创建方法 基于已有镜像创建基于本地模板创建基于Dockerfile创建 &#xff08;实际环境中用的最多&#xff09; 2.1 基于已有镜像的创建 将容器里面运行的程序及运行环境打包生成新的镜像 …

网络工程师笔记10 ( RIP / OSPF协议 )

RIP 学习路由信息的时候需要配认证 RIP规定超过15跳认定网络不可达 链路状态路由协议-OSPF 1. 产生lsa 2. 生成LSDB数据库 3. 进行spf算法&#xff0c;生成最有最短路径 4. 得出路由表

IOS开发0基础入门UIkit-1cocoapod安装、更新和使用 , 安装中出现的错误及解决方案 M1或者M2安装cocoapods

cocoapod是ios开发时常用的包管理工具 1.M1或者是M2系统安装cocoapods先操作一下两个设置 1、打开访达->应用->实用工具->终端->右键点击终端->显示简介->勾选使用 Rosetta 打开&#xff0c;关闭终端&#xff0c;重新打开。 2、打开访达->应用->Xcod…

如何制作一个分销商城小程序_揭秘分销商城小程序的制作秘籍

打造赚钱神器&#xff01;揭秘分销商城小程序的制作秘籍 在这个数字化高速发展的时代&#xff0c;拥有一个属于自己的分销商城小程序&#xff0c;已成为众多商家和创业者的必备利器。它不仅能够快速搭建起自己的在线销售渠道&#xff0c;还能够利用分销模式&#xff0c;迅速裂…