当前位置: 首页 > news >正文

C++数据结构之BST(二叉搜索树)的实现

目录

  • BST 的方法
  • 摘要
  • 查找节点
      • 四个引用,都有妙用
      • 递归版
      • 非递归版
  • 插入节点
      • 利用search的返回值
      • 更新高度的注意事项
      • 插入算法的完整代码
  • 删除节点
      • 框架
      • 单分支,直接替代
      • 双分支,化繁为简
      • 代码
  • code BST

预告:本文是后续实现各种各样平衡二叉搜索树的铺垫。

BST 的方法

方法 功能 参数 返回值
search 查找 T const & val BinNode * &
insert 插入 T const & val BinNode *
remove 移除 T const & val bool

摘要

  1. 虚函数,方便派生类进行重写。
  2. 全局静态模板函数,适用于AVL,Splay,RedBlack等各种BST
  3. 这里的remove一看就是对外的,因为参数终于不是指针了,而是值。需要我们先找位置。

查找节点

四个引用,都有妙用

看到searchIn的声明,居然全都是引用类型。

static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val)

列举这四个引用各自的功能——

返回值引用:插入节点时,这个引用相当于插入位置,后续我们将新节点的指针赋给到这个返回值,父节点的左右孩子之一就会连上新节点。

BinNode<T> * & rt:如果这个不是引用,返回值返回的就是一个仅在函数内部的局部变量(即形参),后续改写这个引用值时,会发生错误。

BinNode<T> * & hot_node:在递归中随深度不断更新这个记忆热点,也是为了方便插入算法,等到最后退出时hot存的是插入位置的父节点。

T const & val:传递引用变量可以提速,为了不误改,前面加上const做约束。

递归版

		virtual BinNode<T> * & search(T const & val){return searchIn(BinTree<T>::root, hot, val);}static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val){if (!rt || rt->data == val) return rt; // 返回的是引用hot_node = rt; //在递归中随深度不断更新if (val < rt->data) return searchIn(rt->left, hot_node, val);else return searchIn(rt->right, hot_node, val);}

非递归版

尾递归转迭代,略。

插入节点

利用search的返回值

有了查找节点算法中“记忆热点”hot的设计,经过search()的运行,就可以得到插入位置的父节点。或许应该记得BinTree里写过的几个函数:insertAsLeft()insertAsRight(),我们只需要将valhot->data做比较即可。在这里,我们换一种写法——不浪费search的返回值。你知道,查找一旦失败,返回值就是NULL的引用,利用它,就无需在insert()中判断究竟应该插入到hot的左边还是右边。

先找到插入位置,X的类型必须是引用,后续我们将新节点的指针赋给到X,hot的左右孩子之一就会连上新节点。

BinNode<T> * & X = search(val); 

下面这一句话将 “父->子” “子->父” 相互关系都连接好了。

X = new BinNode(val, hot); 

更新高度的注意事项

更新高度由于之前做的优化,检测到某处更新后与更新前高度一致则不会再上行更新,所以高度更新要给父节点更新,即updateHighAbove(hot),如果给了X更新,那就不会继续下去。

插入算法的完整代码

		virtual BinNode<T> * insert(T const & val){BinNode<T> * & X = search(val); //为了找到插入位置if (!X){X = new BinNode(val, hot); //这一句话将两个关系连接// 不要忘记BinTree<T>::size++;updateHighAbove(hot);}return X;}

insert()的返回值是X,但返回类型是BinNode<T> *,并不是引用,这在语法中是允许的。所返回的东西仅仅在数值上与X相同,但与X完全脱离了关系。

删除节点

框架

		virtual bool remove(T const & val){BinNode<T> * & X = search(val);if (!X) //树里没有val{return false;}else{removeAt(X, hot);BinTree<T>::size--;updateHighAbove(hot);return true;}}

单分支,直接替代

在这里插入图片描述

双分支,化繁为简

还是想,哪一个节点替代被删节点的位置。那一定是直接后继。求中序遍历下的直接后继。
在这里插入图片描述

代码

		static void removeAt(BinNode<T> * X, BinNode<T> * & hot_node){// hot_node指向要被删除的父亲BinNode<T> * del_node; // 实际要被删除的节点BinNode<T> * succ_node; // 实际要被删除的节点的接替者if (!X->left){del_node = X;succ_node = X->right}else if (!X->right){del_node = X;succ_node = X->left;}else // 双分支情况{ // 找到中序的直接后继del_node = succ(X);succ->node = del_node->right;swap(del_node->data, X->data);BinNode<T>::fromParentTo(del_node) = succ;}hot = del_node->parent;if (succ_node) succ->parent = hot;delete del_node;return succ;}

code BST

# pragma once# include "BinTree.h"template <typename T>
class BST : public BinTree<T> {public:virtual BinNode<T> * & search(T const & val){return searchIn(BinTree<T>::root, hot, val);}virtual BinNode<T> * insert(T const & val){BinNode<T> * & X = search(val); //为了找到插入位置if (!X){X = new BinNode(val, hot); //这一句话将两个关系连接// 不要忘记BinTree<T>::size++;updateHighAbove(hot);}return X;}virtual bool remove(T const & val){BinNode<T> * & X = search(val);if (!X) //树里没有val{return false;}else{removeAt(X, hot);BinTree<T>::size--;updateHighAbove(hot);return true;}}static void removeAt(BinNode<T> * X, BinNode<T> * & hot_node){// hot_node指向要被删除的父亲BinNode<T> * del_node; // 实际要被删除的节点BinNode<T> * succ_node; // 实际要被删除的节点的接替者if (!X->left){del_node = X;succ_node = X->right}else if (!X->right){del_node = X;succ_node = X->left;}else // 双分支情况{ // 找到中序的直接后继del_node = succ(X);succ->node = del_node->right;swap(del_node->data, X->data);BinNode<T>::fromParentTo(del_node) = succ;}hot = del_node->parent;if (succ_node) succ->parent = hot;delete del_node;return succ;}static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val){if (!rt || rt->data == val) return rt; // 返回的是引用hot_node = rt; //在递归中随深度不断更新if (val < rt->data) return searchIn(rt->left, hot_node, val);else return searchIn(rt->right, hot_node, val);}protected:BinNode<T> * hot; // 命中节点的父亲};

相关文章:

C++数据结构之BST(二叉搜索树)的实现

目录 BST 的方法摘要查找节点四个引用&#xff0c;都有妙用递归版非递归版 插入节点利用search的返回值更新高度的注意事项插入算法的完整代码 删除节点框架单分支&#xff0c;直接替代双分支&#xff0c;化繁为简代码 code BST 预告&#xff1a;本文是后续实现各种各样平衡二叉…...

QT以管理员身份运行

以下配置后&#xff0c;QT在QT Creator调试时&#xff0c;或者生成的.exe程序&#xff0c;都将会默认以管理员身份运行。 一、MSVC编译器 1、在Pro文件中添加以下代码&#xff1a; QMAKE_LFLAGS /MANIFESTUAC:\"level\requireAdministrator\ uiAccess\false\\" …...

java中的缓冲流

Java.io.BufferedOutputStream 字节缓冲输出流&#xff0c;继承自OutputStream 构造方法&#xff1a; BufferedOutputStream (OutputStream out) 创建一个新的缓冲输出流&#xff0c;将数据写入指定的底层输出流BufferedOutputStream (OutputStream out, int size) 创建一个新…...

【小吉带你学Git】idea操作(1)_配置环境并进行基本操作

&#x1f38a;专栏【Git】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Counting Stars 】 欢迎并且感谢大家指出小吉的问题&#x1f970; 文章目录 &#x1f354;环境准备⭐配置Git忽略文件&#x1f384;方法&#x1f33a;创…...

DP-GAN-生成器代码

首先看一下数据生成&#xff1a; 在预处理阶段会将label经过ont-hot编码转换为35个通道&#xff0c;即每个通道都是由&#xff08;0,1&#xff09;组成。 在train文件中&#xff0c;对生成器和判别器分别进行更新&#xff0c;根据loss的不同&#xff0c;分别计算对于的损失&a…...

2020-2023中国高等级自动驾驶产业发展趋势研究

1.1 概念界定 2020-2023中国高等级自动驾驶产业发展趋势研究Trends in China High-level Autonomous Driving from 2020 to 2023自动驾驶发展过程中&#xff0c;中国出现了诸多专注于研发L3级以上自动驾驶的公司&#xff0c;其在业界地位也越来越重要。本报告围绕“高等级自动…...

JDK19 - synchronized关键字导致的虚拟线程PINNED

JDK19 - synchronized关键字导致的虚拟线程PINNED 前言一. PINNED是什么意思1.1 synchronized 绑定测试1.2 synchronized 关键字的替代 二. -Djdk.tracePinnedThreads的作用和坑2.1 死锁案例测试2.2 发生原因的推测2.3 总结 前言 在 虚拟线程详解 这篇文章里面&#xff0c;我们…...

用msys2安装verilator并用spinal进行仿真

一 参考 SpinalHDL 开发环境搭建一步到位(图文版) - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)https://aijishu.com/a/1060000000255643Setup and installation of Verilator — SpinalHDL documentation...

【ARM64 常见汇编指令学习 13 -- ARM 汇编 ORG 伪指令学习】

文章目录 ARM ORG 指令介绍UEFI 中对 ORG 指令的使用 ARM ORG 指令介绍 在ARM汇编中&#xff0c;"org"是一个汇编器伪指令&#xff0c;用于设置下一条指令的装入地址。"org"后面跟着的是一个表达式&#xff0c;这个表达式的值就是下一条指令的装入地址。如…...

Vue使用QuillEditor富文本编辑器问题记录

1.内容绑定的问题 绑定内容要使用 v-model:content"xxx" 的形式。 2.设置字体字号 字体以及字号大小的设置需要先注册。 <script> import { QuillEditor,Quill } from vueup/vue-quill import vueup/vue-quill/dist/vue-quill.snow.css; // 设置字体大小 c…...

spring AOP学习

概念 面向切面编程横向扩展动态代理 相关术语 动态代理 spring在运行期&#xff0c;生成动态代理对象&#xff0c;不需要特殊的编译器 Spring AOP的底层就是通过JDK动态代理或者CGLIb动态代理技术为目标Bean执行横向织入 目标对象实现了接口&#xff0c;spring使用JDK的ja…...

16.M端事件和JS插件

16.1移动端 移动端也有自己独特的地方 ●触屏事件touch (也称触摸事件)&#xff0c;Android 和I0S都有。 ●touch对象代表一个触摸点。触摸点可能是一根手指&#xff0c;也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。 ●常见的触屏事件如下: …...

Zebec APP:构建全面、广泛的流支付应用体系

目前&#xff0c;流支付协议 Zebec Protocol 基本明确了生态的整体轮廓&#xff0c;它包括由其社区推动的模块化 Layer3 构架的公链 Nautilus Chain、流支付应用 Zebec APP 以及 流支付薪酬工具 Zebec payroll 。其中&#xff0c;Zebec APP 是原有 Zebec Protocol 的主要部分&a…...

Spark 3.1.1 遇到的 from_json regexp_replace组合表达式慢问题的解决

背景 目前公司在从spark 2.4.x升级到3.1.1的时候&#xff0c;遇到了一类SQL极慢的情况&#xff0c;该SQL的如下(只列举了关键的)&#xff1a; select device_personas.* from(selectdevice_id, ads_id, from_json(regexp_replace(device_personas, (?<(\\{|,))"devic…...

Docker 容器常用的命令和操作

1.容器操作 - 运行容器: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 示例&#xff1a; docker run -it --rm ubuntu /bin/bash - 查看正在运行的容器: docker ps [OPTIONS] 示例&#xff1a; docker ps -a - 停止容器: docker stop CONTAINER [CONTAINER...] 示…...

iTOP-RK3568开发板Windows 安装 RKTool 驱动

在烧写镜像之前首先需要安装 RKTool 驱动。 RKTool 驱动在网盘资料“iTOP-3568 开发板\01_【iTOP-RK3568 开发板】基础资料 \02_iTOP-RK3568 开发板烧写工具及驱动”路径下。 驱动如下图所示&#xff1a; 解压缩后&#xff0c;进入文件夹&#xff0c;如下图所示&#xff1a;…...

nginx rtmp http_flv直播推流

安装配置nginx yum install epel-release -y sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm yum install ffmpeg ffmpeg-devel -y yum install gcc -y yum install pcre pcre-devel -y yum install openssl open…...

Day50 算法记录| 动态规划 17(子序列)

这里写目录标题 647. 回文子串516.最长回文子序列总结 647. 回文子串 1.动态规划和2.中心扩展 这个视频是基于上面的视频的代码 方法1:动态规划 布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#xff0c;如…...

RabbitMQ:概念和安装,简单模式,工作,发布确认,交换机,死信队列,延迟队列,发布确认高级,其它知识,集群

1. 消息队列 1.0 课程介绍 1.1.MQ 的相关概念 1.1.1.什么是MQ MQ(message queue&#xff1a;消息队列)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是message 而已&#xff0c;还是一种跨进程的通信机制…...

小研究 - 基于解析树的 Java Web 灰盒模糊测试(二)

由于 Java Web 应用业务场景复杂, 且对输入数据的结构有效性要求较高, 现有的测试方法和工具在测试Java Web 时存在测试用例的有效率较低的问题. 为了解决上述问题, 本文提出了基于解析树的 Java Web 应用灰盒模糊测试方法. 首先为 Java Web 应用程序的输入数据包进行语法建模创…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

【第二十一章 SDIO接口(SDIO)】

第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...