【数据结构-二叉搜索树的增删查改】

news2024/12/27 10:59:59

在这里插入图片描述

🌈个人主页:努力学编程’
个人推荐:基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解
学好数据结构,刷题刻不容缓:点击一起刷题
🌙心灵鸡汤总有人要赢,为什么不能是我呢
在这里插入图片描述

🌈二叉搜索树

二叉搜索树又称二叉排序树,从节点的个数上又可分为两种,空树或者具有一定性质的树,这种具有特殊性质的树具有特点:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

在这里插入图片描述

根节点27的左子树的所有的节点的值都小于27,右子树的所有节点的值都大于27,这也是为什么我们叫他二叉排序树的原因。当然他的每个子树也都满足这个性质。

⚡⚡⚡特别说明:当我们使用中序遍历搜索二叉树的时候,遍历所得的数组是一个有序数组。

🌈二叉搜索树-查找

如何在二叉搜索树中查找数值呢,他和普通二叉树有区别吗?

  • 当然我们在查找索索二叉树数值的时候,我们理应利用它结构上的特点进行查找:
  • 节点为空: 返回fasle;
  • 节点不为空:Key>root.val 在根节点的右侧进行查找
  • 节点不为空: Key<root.val 在根节点的左侧进行查找

在这里插入图片描述

🌈二叉搜索树-插入

在二叉搜索树当中,插入数据分为两步:找到要插入数据的位置,插入数据。

  • 如何找到插入数据的位置是最重要的一步,其实这步和查找有一定的相似度。我们将带插入数据与当前的根节点进行比较,根据大小关系,在树的左右子树进行查找。

  • 直到找到我们需要插入点的位置,但是只要你实际操作这个过程就会发现我们无法直接定位到需要插入数据的位置,只能定位到带插入位置的下个一位置,所以我们需要创建一个指针定位到插入数据指针的上一个位置,这样就找到了待插入的位置.

  • 若节点为空,直接插入节点!!!

在这里插入图片描述

  • 使用parent标记带插入的位置,直接进行插入:
    在这里插入图片描述

🌈二叉搜索树-删除

对于删除操作,比较麻烦,需要分不同的几种情况进行讨论,待删除的节点cur,待删除的数据的父节点parent:

  • cur.left == null:

  • cur 是 root: 则 root = cur.right

  • cur 不是 root,cur 是 parent.left: 则 parent.left = cur.right

  • cur 不是 root,cur 是 parent.right 则 parent.left = cur.left

  • cur.right==null:

  • cur是root: 则 则 root = cur.left

  • cur 不是 root,cur 是 parent.left,则 parent.left = cur.left

  • cur 不是 root,cur 是 parent.right,则 parent.right = cur.left

  • cur.left != null && cur.right != null:

  • 需要使用替换法进行删除,即在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被
    删除节点中,再来处理该结点的删除问题

🌈搜索二叉树-模拟实现:

针对于搜索二叉树的增删查改的基础操作代码的实现:

public class BinarySearchTree {
    static class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root = null;

    public TreeNode search(int key) {
        TreeNode cur = root;
        while (cur != null) {
            if(cur.val < key) {
                cur = cur.right;
            }else if(cur.val > key) {
                cur = cur.left;
            }else {
                return cur;
            }
        }
        return null;
    }

    public void insert(int val) {
        TreeNode node = new TreeNode(val);
        if(root == null) {
            root = node;
            return;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {
            if(cur.val < val) {
                parent = cur;
                cur = cur.right;
            }else if(cur.val > val) {
                parent = cur;
                cur = cur.left;
            }else {
                return;
            }
        }
        //parent 指向的节点 就是 需要插入的节点位置 的 父亲节点
        if(parent.val > val) {
            parent.left = node;
        }else {
            parent.right = node;
        }
    }
    //key = 10;
    public void remove(int key) {
        TreeNode parent = null;
        TreeNode cur = root;
        while (cur != null) {
            if(cur.val < key) {
                parent = cur;
                cur = cur.right;
            }else if(cur.val > key) {
                parent = cur ;
                cur = cur.left;
            }else {
                removeNode(parent,cur);
                return;
            }
        }
    }
    private void removeNode(TreeNode parent,TreeNode cur) {
        if(cur.left == null) {
            if(cur == root) {
                root = cur.right;
            }else if(cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if(cur.right == null) {
            if(cur == root) {
                root = cur.left;
            }if(cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            TreeNode target = cur.right;
            TreeNode targetP = cur;
            while (target.left != null) {
                targetP = target;
                target = target.left;
            }
            cur.val = target.val;
            if(target == targetP.left) {
                targetP.left = target.right;
            }else {
                targetP.right = target.right;
            }
        }
    }
}

🌈二叉搜索树-算法性能分析

针对我们上面的基础操作,插入和删除都需要查找操作,针对二叉树的查找,我们需要根据树的结构进行分析,不同的结构时间复杂度也会不同。

⚡⚡⚡完全二叉树
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为: l o g N logN logN
在这里插入图片描述
💧💧💧右单支
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:2/N
在这里插入图片描述

🌈二叉搜索树-力扣刷题

在这里插入图片描述

解题思路:我们解决二叉树问题,优先思考的是利用递归的套路解决问题,由于这是一颗搜索二叉树,我们也应当利用树的特点,解决这个问题:

递归的套路:

  • 方法的返回值和参数
  • 递归结束的条件
  • 单层遍历
  • 结合搜索二叉树的性质解决问题
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
         if(root==null||root.val==val) return root;
         TreeNode result=null;
         if(root.val>val) result=searchBST(root.left,val);
         if(root.val<val) result=searchBST(root.right,val);
         return result;
    }
}

在这里插入图片描述
在这里插入图片描述
解题思路:是否是一颗搜索二叉树,应当使用其定义进行判断,左子树必须小于根节点的值,右子树所有的节点必须大于根节点的值。当然他的每一棵子树都必须满足这个特性。

那么我们就可以利用递归实现这个过程,
所以递归的方法的返回值:首先是boolean ,参数是根节点,左右节点,
结束条件:root==null return true;
if(node.val<=lower||node.val>=upper) return false;
单层遍历:validBST(lower, root.val, root.left) && validBST(root.val, upper, root.right);

class Solution {
    public boolean isValidBST(TreeNode root) {
        return validBST(Long.MIN_VALUE, Long.MAX_VALUE, root);
    }
    boolean validBST(long lower, long upper, TreeNode root) {
        if (root == null) return true;
        if (root.val <= lower || root.val >= upper) return false;
        return validBST(lower, root.val, root.left) && validBST(root.val, upper, root.right);
    }
}

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

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

相关文章

IPFoxy Tips:什么是静态住宅IP?静态ISP代理指南

静态住宅代理&#xff08;也称为静态ISP代理&#xff09;是最流行的代理类型之一。它们也是隐藏您的身份并保持在线匿名的最佳方法之一。您为什么要使用住宅代理而不是仅使用常规代理服务&#xff1f;下面我具体分享。 一、什么是静态住宅代理&#xff1f; 首先&#xff0c;我…

网络编程基础回顾

计算机网络&#xff08;5&#xff09;&#xff1a;运输层 OSI 模型与 TCP/IP 协议 OSI七层协议模型 (open system interconnection) 应用层&#xff1a;为应用数据提供服务表示层&#xff1a;数据格式转化&#xff0c;数据加密会话层&#xff1a;建立、维护和管理会话传输层&…

学习100个Unity Shader (17) --- 深度纹理

文章目录 效果shader部分C# 部分理解参考 效果 shader部分 Shader "Example/DepthTexture" {SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _CameraDepthTexture;struct a2v{float4 pos : POSITIO…

Web3 ETF软件开发

开发Web3 ETF软件涉及到金融、法律和技术等多个领域的专业知识&#xff0c;因此存在以下技术难点&#xff0c;开发Web3 ETF软件是一项复杂的技术挑战&#xff0c;需要综合考虑各种因素。开发人员需要具备较强的技术能力和跨学科知识才能成功开发Web3 ETF软件。北京木奇移动技术…

汽车电子零部件(13):BMS电池管理系统

前言: 电池管理系统(BMS)确保电动汽车(EV)的能量分配安全高效。目前流行电动汽车中使用的有四种主要BMS架构,BMS与充电基础设施互为集成关系。BMS主要管理 的是电池组,电池组由很多电芯组成,比如下图是H/EV电池组的主要部件,显示了电池、连接、控制电路和包装的总体布…

python中w、r表示什么意思

文件读写就是一种常见的IO操作。 文件读写操作步骤 不同的编程语言读写文件的操作步骤大体都是一样的&#xff0c;都分为以下几个步骤&#xff1a; 1&#xff09;打开文件&#xff0c;获取文件描述符&#xff1b; 2&#xff09;操作文件描述符--读/写&#xff1b; 3&#…

苍穹外卖Day06笔记

疯玩了一个月&#xff0c;效率好低&#xff0c;今天开始捡起来苍穹外卖~ 1. 为什么不需要单独引入HttpClient的dependency&#xff1f; 因为我们在sky-common的pom.xml中已经引入了aliyun-sdk-oss的依赖&#xff0c;而这个依赖低层就引入了httpclinet的依赖&#xff0c;根据依…

最详尽的网络安全学习路线!涵盖所有技能点,带你成为网安专家!

目录 零基础小白&#xff0c;到就业&#xff01;入门到入土的网安学习路线&#xff01; 建议的学习顺序&#xff1a; 一、夯实一下基础&#xff0c;梳理和复习 二、HTML与JAVASCRIPT&#xff08;了解一下语法即可&#xff0c;要求不高&#xff09; 三、PHP入门 四、MYSQL…

ssm115乐购游戏商城系统+vue

毕业生学历证明系统 设计与实现 内容摘要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统毕业生学历信息管理难…

小巧简单实用的Linux端口转发工具Rinetd

Linux下实现端口转发有很多种方法&#xff0c;尤其是在可以联网的情况下&#xff0c;更是容易。最近在资源受限的定制系统中&#xff0c;找到一个方便离线安装和使用的端口转发工具Rinetd&#xff0c;安装包仅几十K&#xff0c;而且有很多版本的Linux发行系统的支持。 1、安装…

安科瑞AMC16-DETT 基站直流电能计量模块

AMC16-DETT 基站直流电能计量模块主要是针对有共享需求&#xff0c;且开关电源无分用户电量计量功能的基站而设计的。仪表可对六个回路的直流电能进行计量&#xff0c;并可为配套的霍尔传感器提供工作电流&#xff0c;同时可通过上位机软件实现零漂校准&#xff0c;具有遥测、遥…

RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决方法二

参考 RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决 前言 rk3568 rockchip 提供的 u-boot&#xff0c;默认的设备树需要读取 单独分区 resouce.img 镜像中的 设备树文件&#xff0c;也就是 Linux 内核的设备树 dtb 文件&#xff0c;gmac 网络才能正常的 ping 通…

Applied Spatial Statistics(四)点模式分析-KDE 分析和距离函数

Applied Spatial Statistics&#xff08;四&#xff09;点模式分析-KDE 分析和距离函数 ---- 1853年伦敦霍乱爆发 在此示例中&#xff0c;我将演示如何使用 John Snow 博士的经典霍乱地图在 Python 中执行 KDE 分析和距离函数。 感谢 Robin Wilson 将所有数据数字化并将其转…

mysql查询表信息(表名、表结构、字段信息等)

MySQL中&#xff0c;您可以使用以下SQL查询数据库的表信息或者某个表中具体的信息&#xff0c;例如&#xff1a;字段、字段描述、索引等&#xff0c;以下为具体的SQL&#xff1a; 1、查询数据库所有表信息&#xff08;表名/表描述&#xff09; SELECTtable_name name,TABLE_C…

第03章 二进制、八进制、十进制、十六进制之间转换

3.1 二进制及十进制的由来 3.2 二进制、十进制、八进制、十六进制的表示方法 3.3 二进制和十进制之间的相互转换 3.4 二进制和八进制之间的转换 3.5 二进制和十六进制之间的转换 3.6 二进制算术运算和逻辑运算

JavaScript手写专题——图片懒加载、滚动节流、防抖手写

图片懒加载场景&#xff1a;在一些图片量比较大的网站&#xff08;比如电商网站首页&#xff0c;或者团购网站、小游戏首页等&#xff09;&#xff0c;如果我们尝试在用户打开页面的时候&#xff0c;就把所有的图片资源加载完毕&#xff0c;那么很可能会造成白屏、卡顿等现象&a…

新版security demo(二)前端

写这篇博客&#xff0c;刚好换了台电脑&#xff0c;那就借着这个demo复习下VUE环境的搭建。 一、前端项目搭建 1、安装node 官网下载安装即可。 2、安装脚手架 npm install -g vue-cli 使用脚手架搭建一个demo前端项目 vue init webpack 项目名称 3、安装依赖 这里安装…

完成单位投稿任务找投稿渠道不用精选10个1个就够了

在单位担任信息宣传员的这几年,我深刻体会到了“笔耕不辍”的艰辛与挑战。起初,面对单位的宣传需求,我遵循传统的投稿路径,即通过电子邮件的方式,一家接一家地向各大媒体投递稿件。那时的我,以为只要稿件质量上乘,自然能够获得青睐,却未曾料到,这是一条漫长而曲折的道路。 邮箱…

一键审计 web 日志(teler)

在 web 系统遭受攻击之后&#xff0c;通常要审计 web 日志来寻找蛛丝马迹&#xff0c;那么有没有可以满足需求的自动化工具呢&#xff1f;今天就来尝试一款开源工具 teler&#xff0c;项目地址&#xff1a; https://github.com/kitabisa/teler/ 先来看一张作者测试图&#xff1…

如何在电脑中截屏【攻略】

如何在电脑中截屏【攻略】 前言版权推荐如何在电脑中截屏电脑工具截屏键&#xff1a;PrtScQQ截屏快捷键&#xff1a;CtrlAltA微信截屏快捷键&#xff1a;AltAQQ浏览器截屏快捷键&#xff1a;CtrlShiftXEdge浏览器截屏快捷键&#xff1a;CtrlShiftS 最后 前言 2024-5-9 21:31:3…