搜索树概念及操作

news2024/11/16 5:36:25

目录

一. .搜索树

1.1 概念

1.2 操作1 查找

 1.3 操作2 插入

1.4 操作3 删除

1.5 性能分析

1.6 和 java 类集的关系


 

一. .搜索树

1.1 概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 :
  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

 

1.2 操作1 查找

思路:

  1. 从根节点出发, 如果根节点大于val值, 说明要找的val小于根在根的左边, 所以cur = cur.left
  2. 如果根节点小于val值, 说明要找的val大于根在根的右边, 所以cur = cur.right
  3. 如果根节点等于val值, 说明找到了, 直接返回true
  4. 循环搜索下去, 直到cur == null停止, 说明找不到val值,返回false
 public boolean search(int val){
        TreeNode cur = root;
        while(cur != null){
            if(cur.val > val){
                cur = cur.left;
            }else if(cur.val < val){
                cur = cur.right;
            }else{
                return true;
            }
        }
        return false;
    }

 1.3 操作2 插入

思路:

  1. 如果是一颗空树, 直接将结点插入即可
  2. 找到合适的位置: 和查找的方法类似, 先循环找到该节点应该插入的位置, 如果根节点大于val值, cur = cur.left, 根节点小于val值, cur = cur.right, 根节点等于val值, 则直接返回, 因为搜索树是不允许有相同的节点的, 直到cur== null, 说明该节点应该插入在此
  3. 但是, 如果我们不知道此节点的父亲节点, 那么我们将没法插入, 所以我们要定义一个parent结点, parent始终等于cur的父亲节点
  4. 如果val值 < parent.val, 则插入到parent.left, 如果val值 > parent.val, 则插入到parent.right
public void insert(int val){
        if(root == null){
            root = new TreeNode(val);
            return;
        }
        TreeNode node = new TreeNode(val);
        TreeNode cur = root;
        TreeNode parent = null;
        while(cur != null){
            if(cur.val > val){
                parent = cur;
                cur = cur.left;
            }else if(cur.val < val){
                parent = cur;
                cur = cur.right;
            }else{
                return;
            }
        }
        if(parent.val > val){
            parent.left = node;
        }else{
            parent.right = node;
        }
    }

1.4 操作3 删除

思路:

设删除节点为cur, cur的父亲节点为parent

cur结点一共分为三种情况:

情况1. cur.left == null

cur.left == null时, 也分成三种情况:

        1)cur == root, 只需将root = cur.right

        2)cur ! =root && cur == parent.left, parent.left = cur.right

        3)cur ! =root && cur == parent.right, parent.right = cur.right

情况2. cur.right == null

cur.right == null时, 同样也分成三种情况:(与上面相对应)

        1)cur == root, 只需将root = cur.left

        2)cur ! =root && cur == parent.left,parent.left = cur.left

        3)cur ! =root && cur == parent.right,parent.right = cur.left

情况3. cur左右节点都不为空

当cur左右节点都不为空时, 我们采用的方法是替换法:

法一: 找到cur结点左子树的最大值, 将cur的值替换成这个值, 再将此结点删除

法二: 找到cur结点右子树的最小值, 将cur的值替换成这个值, 再将此结点删除

问题一:为什么要找左子树的最大值或右子树的最小值?

答:

上面这棵树, 删除15, 正常我们要找的14或20, 得到:

可以看到, 替换之后, 依旧满足搜索树的定义, 左子树都比根小, 右子树都比根大

如果我们选择11, 那么:

发现违背了搜索树的定义!

问题二:为什么要使用替换法?

答:假设我们使用法一, 因为此节点时左子树的最大值, 那么说明该节点没有右子树, cur.right == null, 那么删除该节点的方法就非常简单啦, 就是上面的第2种情况

思路(假设使用法一, 找左子树的最大值):

  1. 找到要删除的结点cur
  2. 找左子树最大值: 定义一个指针t, 令t = cur.left(因为我们要找左子树), 让t去找左子树的最大值, 即如果t有右子树, 则t = t.right, 直到t没有右子树
  3. 替换: 此时t为左子树的最大值, 将t.val = cur.val
  4. 删除: 还要定义一个tp, 使tp始终等于t的父亲节点, 就回到了情况2: 如果t == tp.left, tp.left = t.left ; 如果t == tp.right, tp.right = t.left
public void remove(int val){
        TreeNode cur = root;
        TreeNode parent = null;
        while(cur != null){
            if(cur.val > val){
                parent = cur;
                cur = cur.left;
            }else if(cur.val < val){
                parent = cur;
                cur = cur.right;
            }else{
                removeNode(parent,cur);
                return;
            }
        }
    }
    public void removeNode(TreeNode parent, TreeNode cur){
//情况1
        if(cur.left == null){
            if(cur == root){
                root = cur.right;
            }else if(cur == parent.left){
                parent.left = cur.right;
            }else if(cur== parent.right){
                parent.right = cur.right;
            }
//情况2
        }else if(cur.right == null){
            if(cur == root){
                root = cur.left;
            }else if(cur == parent.left){
                parent.left = cur.left;
            }else if(cur == parent.right){
                parent.right = cur.left;
            }
//情况3
        }else{
            TreeNode t = cur.left;
            TreeNode tp = cur;
            while(t.right != null){
                tp = t;
                t = t.right;
            }
            cur.val  = t.val;
            if(t == tp.right){
                tp.right = t.left;
            }else{
                tp.left = t.left;
            }
        }
    }

1.5 性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有 n 个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:\log_{2}N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2
问题:如果退化成单支树,二叉搜索树的性能就失去了。那能否进行改进,不论按照什么次序插入关键码,都可以是二叉搜索树的性能最佳?
答:AVL树(后续介绍)

1.6  java 类集的关系

TreeMap TreeSet java 中利用搜索树实现的 Map Set ;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证,关于红黑树的内容后序介绍。

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

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

相关文章

C语言程序练习——汉诺塔递归

1. 题目 在终端输入汉诺塔层数n&#xff0c;实现将n层汉诺塔通过三座塔座A、B、C进行排列 2. 代码 #include <stdio.h>int hannuota(int len, int str, int tmp, int dst) {if (1 len){printf("%c -> %c\n", str, dst);}else{hannuota(len-1, str, dst, …

【每日一题】2024年3月汇编(上)

3.1【2369】检查数组是否存在有效划分 2369. 检查数组是否存在有效划分https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/ 1.这样的判断可以用动态规划来解决&#xff0c;用一个长度为(n1) 的数组来记录 是否存在有效划分&#xff0c;dp[i]…

单页面应用部署到iis上可以正常打开,刷新就404

当您遇到Dumi打包的网站部署到IIS上可以正常打开首页,但刷新页面时出现404错误的情况,这通常与以下几个方面有关: 路由处理: Dumi生成的项目通常基于SPA(Single Page Application)架构,使用前端路由来实现无刷新导航。这意味着大部分页面切换是在浏览器层面完成的,而不…

循环神经网络(RNN):处理序列数据的利器

目录 1. 引言 2.RNN原理与时间步展开 3.LSTM与GRU工作机制与优势 3.1.LSTM&#xff08;Long Short-Term Memory&#xff09; 3.2.GRU&#xff08;Gated Recurrent Unit&#xff09; 4.应用案例 4.1文本生成 4.2情感分析 5.总结 1. 引言 循环神经网络&#xff08;Recurr…

el-select动态禁用

在一个el-form表单中有5个el-form-item; 每个el-form-item是一个el-select控件&#xff1b; 这5个el-select控件遵循这样的规则&#xff0c;都是使用同一个list集合&#xff0c;如果第一个el-select选择了list中的某一项&#xff0c;那么这一项就被禁用&#xff1b;其他的el-…

【3D目标检测】Det3d—SE-SSD模型训练(前篇):KITTI数据集训练

SE-SSD模型训练 1 基于Det3d搭建SE-SSD环境2 自定义数据准备2.1 自定义数据集标注2.2 训练数据生成2.3 数据集分割 3 训练KITTI数据集3.1 数据准备3.2 配置修改3.3 模型训练 1 基于Det3d搭建SE-SSD环境 Det3D环境搭建参考&#xff1a;【3D目标检测】环境搭建&#xff08;OpenP…

【Entity Framework】Code First 数据批注

【Entity Framework】Code First 数据批注 文章目录 【Entity Framework】Code First 数据批注一、概述二、模型二、键Key三、组合键四、外键-ForeigKey第一种&#xff1a;指定导航属性&#xff0c;会自动生成外键&#xff0c;命名规则为&#xff1a;“对象名称_主键名“第二种…

YOLOv9改进策略:注意力机制 | 二阶通道注意力机制(Second-order Channel Attention,SOCA),实现单图超分效果

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;CVPR_2019 SOCA注意力&#xff0c;一种基于二阶通道注意力机制&#xff0c;能够单幅图像超分辨率&#xff0c;从原理角度分析能够在小目标检测领域实现大幅涨点效果&#xff01;&#xff01;&#xff01; &am…

文件编辑命令—vim

1.vim vim 是vi的升级版本.vi 文件名(vi方向键用不了) vim 的官方网站 (welcome home : vim online) 自己也说 vim 是一个程序开发工具而不是文字处理软件。 2.安装vim sudo apt install vim 如果出错了:apt update:刷新软件源; 出现"无法获得锁 之类的"sudo rm 文件…

Vit Transformer

一 VitTransformer 介绍 vit : An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale 论文是基于Attention Is All You Need&#xff0c;由于图像数据和词数据数据格式不一样&#xff0c;经典的transformer不能处理图像数据&#xff0c;在视觉领域的应…

【jenkins+cmake+svn管理c++项目】Windows环境安装以及工具配置

一、目标和环境 目标&#xff1a;搭建一个jenkins环境&#xff0c;实现jenkins调用cmake和svn和VS编译c项目&#xff0c;并将生成的库上传svn。 环境&#xff1a;win10虚拟机&#xff08;练习流程用&#xff0c;正式用的话还是放到服务器&#xff09;&#xff0c;VS2017. 二、…

肿瘤靶向肽 iRGD peptide环肽 1392278-76-0 c(CRGDKGPDC)

RGD环肽 c(CRGDKGPDC)&#xff0c;iRGD peptide 1392278-76-0 结 构 式&#xff1a; H2N-CRGDKGPDC-OH(Disulfide Bridge:C1-C9) H2N-Cys-Arg-Gly-Asp-Lys-Gly-Pro-Asp-Cys-COOH(Disulfide Bridge:Cys1-Cys9) 氨基酸个数&#xff1a; 9 C35H57N13O14S2 平均分子量:…

智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码) 源码设计 % ------------------------------------------------------------------------------------------------…

GIS与Python机器学习:开创地质灾害风险评价新纪元

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

55、Qt/事件机制相关学习20240326

一、代码实现设置闹钟&#xff0c;到时间后语音提醒用户。示意图如下&#xff1a; 代码&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), speecher(new QTextToSpeech(t…

【Redis】Redis 介绍Redis 为什么这么快?Redis数据结构Redis 和Memcache区别 ?为何Redis单线程效率也高?

目录 Redis 介绍 Redis 为什么这么快&#xff1f; Redis数据结构 Redis 和Memcache区别 &#xff1f; 为何Redis单线程效率也高&#xff1f; Redis 介绍 Redis 是一个开源&#xff08;BSD 许可&#xff09;、基于内存、支持多种数据结构的存储系统&#xff0c;可以作为数据…

【Linux】从零开始认识进程 — 中下篇

送给大家一句话&#xff1a; 人一切的痛苦&#xff0c;本质上都是对自己无能的愤怒。而自律&#xff0c;恰恰是解决人生痛苦的根本途径。—— 王小波 从零认识进程 1 进程优先级1.1 什么是优先级1.2 为什么要有优先级1.3 Linux优先级的特点 && 查看方式1.4 其他概念 2…

1.6.1 变换

我们要想改变物体的位置&#xff0c;现有解决办法是&#xff0c;每一帧改变物体的顶点并且重配置缓冲区从而使物体移动&#xff0c;但是这样太繁琐&#xff0c;更好的解决方式是使用矩阵&#xff08;Matrix&#xff09;来更好的变换&#xff08;Transform&#xff09;一个物体。…

Python更改Word文档的页面大小

页面大小确定文档中每个页面的尺寸和布局。在某些情况下&#xff0c;您可能需要自定义页面大小以满足特定要求。在这种情况下&#xff0c;Python可以帮助您。通过利用Python&#xff0c;您可以自动化更改Word文档中页面大小的过程&#xff0c;节省时间和精力。本文将介绍如何使…

每日一题 --- 删除链表的倒数第 N 个结点[力扣][Go]

删除链表的倒数第 N 个结点 题目&#xff1a;19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#x…