【深入C++】二叉搜索树

文章目录

  • 什么是二叉搜索树
  • 二叉搜索树的接口
    • 1.查找操作
    • 2.插入操作
    • 3.中序遍历
    • 4.删除操作
  • 所有代码
  • 总结

在这里插入图片描述

在这里插入图片描述

什么是二叉搜索树

二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,其每个节点最多有两个子节点,分别称为左子节点和右子节点。BST具有以下性质:

  1. 左子树的所有节点值都小于根节点的值:即对于每一个节点,其左子树上所有节点的值都比该节点的值小。
  2. 右子树的所有节点值都大于根节点的值:即对于每一个节点,其右子树上所有节点的值都比该节点的值大。
  3. 每个子树也是二叉搜索树:这意味着BST的定义在每个节点的子树上都成立。

形如下面这棵树就是一颗二叉搜索树:

       8/   \3     10/ \      \1   6      14/ \     /4   7   13

二叉搜索树的接口

要写二叉搜索树的接口,我们先得定义一颗二叉搜索树:

定义二叉搜索树的节点:

template<class K>
struct BSTreeNode
{K _key;BSTreeNode<K>* _left;BSTreeNode<K>* _right;BSTreeNode(const K& key):_key(key), _left(nullptr), _right(nullptr){}
};

定义二叉搜索树:

template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:
private:Node* _root = nullptr;
};

1.查找操作

由于二叉搜索树的性质,所以这里我们可以直接用while循环来查找,不需要进行递归来查找:

bool Find(const K& key)
{Node* cur = _root;while (cur){//小于当前节点,在左子树if (cur->_key > key)cur = cur->_left;//大于当前节点,在右子树else if (cur->_key < key) cur = cur->_right;//等于当前节点,返回trueelse return true;}return false;
}

2.插入操作

插入操作我们只需要找到插入的位置,然后插入节点即可,如果没有找到,则返回false,如果找到了并成功插入了,则返回true。

bool Insert(const K& key)
{//没有根节点的情况if (_root == nullptr){_root = new Node(key);return true;}//遍历节点Node* cur = _root;//记录当前节点的父节点Node* parent = nullptr;while (cur){parent = cur;if (cur->_key > key)cur = cur->_left;else if (cur->_key < key) cur = cur->_right;else return false;}//找到插入的地方,直接newcur = new Node(key);//判断插入到父节点的左节点还是右节点if (parent->_key < key) parent->_right = cur;else parent->_left = cur;return true;
}

3.中序遍历

对于中序遍历,我们需要写一个辅助函数,来传递当前this指针对应的root。

void InOrder()
{_InOrder(_root);
}
void _InOrder(Node* root)
{if (root == nullptr) return;_InOrder(root->_left);cout << root->_key << ' ';_InOrder(root->_right);
}

4.删除操作

插入操作分三种情况:
在这里插入图片描述
我们拿下面这个二叉搜索树为例子:
在这里插入图片描述

将节点进行归类:
在这里插入图片描述
我们先讨论删除没有孩子的节点,对于没有孩子的节点我们可以直接进行删除。
其次,我们来讨论删除一个孩子的节点,假如我们删除14,我们需要知道14的父亲,将10和14的左孩子串起来。
在这里插入图片描述
可以将一个孩子的节点归结为这几种情况。
接下来就是有两个孩子的节点:
在这里插入图片描述
我们拿3这个节点为例子:
在这里插入图片描述

删除3节点,我们应该用左子树最大,或者右子树最小进行替换,然后转化成删除左子树最大,或者右子树最小的节点,就相当于把删除有两个孩子的节点转换成删除一个孩子的节点或者没有孩子的节点。

bool Erase(const K& key)
{//三种情况://1.一个孩子//2.没有孩子//3.两个孩子:左子树的最大,右子树的最小//左子树的最左,右子树的最右Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//删除//0-1个孩子的情况if (cur->_left == nullptr){//删除根节点的情况if (parent == nullptr)_root = cur->_right;else{if (parent->_left == cur) parent->_left = cur->_right;else parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){//删除根节点if (parent == nullptr) _root = cur->_left;else{if (parent->_left == cur)parent->_left = cur->_left;else parent->_left = cur->_left;}delete cur;return true;}//两个孩子的情况else{//找右子树最小的节点作为最大的节点Node* rightminp = nullptr;Node* rightmin = cur->_right;//left不为空就一直向left走while (rightmin->_left != nullptr){rightminp = rightmin;rightmin = rightmin->_left;}cur->_key = rightmin->_key;if (rightminp != nullptr) rightminp->_left = rightmin->_right;else cur->_right = rightmin->_right;delete rightmin;return true;}}}return false;
}

删除成功返回true,删除失败没找到则返回false。

所有代码

#pragma once
#include<iostream>
using namespace std;
template<class K>
struct BSTreeNode
{K _key;BSTreeNode<K>* _left;BSTreeNode<K>* _right;BSTreeNode(const K& key):_key(key), _left(nullptr), _right(nullptr){}
};template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public:bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* cur = _root;Node* parent = nullptr;while (cur){parent = cur;if (cur->_key > key)cur = cur->_left;else if (cur->_key < key) cur = cur->_right;else return false;}cur = new Node(key);if (parent->_key < key) parent->_right = cur;else parent->_left = cur;return true;}bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key)cur = cur->_left;else if (cur->_key < key) cur = cur->_right;else return true;}return false;}bool Erase(const K& key){//三种情况://1.一个孩子//2.没有孩子//3.两个孩子:左子树的最大,右子树的最小//左子树的最左,右子树的最右Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//删除//0-1个孩子的情况if (cur->_left == nullptr){//删除根节点的情况if (parent == nullptr)_root = cur->_right;else{if (parent->_left == cur) parent->_left = cur->_right;else parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){//删除根节点if (parent == nullptr) _root = cur->_left;else{if (parent->_left == cur)parent->_left = cur->_left;else parent->_left = cur->_left;}delete cur;return true;}//两个孩子的情况else{//找右子树最小的节点作为最大的节点Node* rightminp = nullptr;Node* rightmin = cur->_right;//left不为空就一直向left走while (rightmin->_left != nullptr){rightminp = rightmin;rightmin = rightmin->_left;}cur->_key = rightmin->_key;if (rightminp != nullptr) rightminp->_left = rightmin->_right;else cur->_right = rightmin->_right;delete rightmin;return true;}}}return false;}void InOrder(){_InOrder(_root);}
private:void _InOrder(Node* root){if (root == nullptr) return;_InOrder(root->_left);cout << root->_key << ' ';_InOrder(root->_right);}Node* _root = nullptr;
};

总结

二叉搜索树(BST)是一种在计算机科学中广泛应用的数据结构,具有高效的查找、插入和删除操作。通过遵循节点值的有序性规则,BST能够在平均情况下实现对数时间复杂度的操作,使其成为处理动态数据集的理想选择。

在本篇博客中,我们详细介绍了二叉搜索树的定义和性质,并通过示例展示了其基本结构。我们还探讨了BST的三大主要操作:插入、查找和删除,并分析了这些操作的实现方法和时间复杂度。

尽管二叉搜索树在平衡状态下具有高效的性能,但在最坏情况下,BST可能会退化成链表。因此,在实际应用中,经常需要采用自平衡二叉搜索树(如AVL树和红黑树)来保证其性能。

通过对BST的深入理解和实践,相信你能够在各种编程场景中灵活运用这一重要的数据结构,从而提高程序的效率和性能。如果你对二叉搜索树有任何疑问或希望了解更多高级应用,欢迎在评论区留言讨论。

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

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

相关文章

Linux环境下dockes使用MongoDB,上传zip文件如何解压并备份恢复到MongoDB数据库中

1、准备 Docker 和 MongoDB 容器 建议主机端口改一下 docker run --name mongodb -d -p 27018:27017 mongo 2. 创建一个工作目录并将 zip 文件上传到dockers容器中 docker cp data.zip mongodb:/data.zip 3. 在 MongoDB 容器中解压 zip 文件&#xff08;也可以解压完再复制…

基础vrrp(虚拟路由冗余协议)

一、VRRP 虚拟路由冗余协议 比如交换机上联两个路由器&#xff0c;由两个路由虚拟出一台设备设置终端设备的网关地址&#xff0c;两台物理路由的关系是主从关系&#xff0c;可以设置自动抢占。终端设备的网关是虚拟设备的ip地址&#xff0c;这样&#xff0c;如果有一台路由设备…

pytorch学习(十一)checkpoint

当训练一个大模型数据的时候&#xff0c;中途断电就可以造成已经训练几天或者几个小时的工作白做了&#xff0c;再此训练的时候需要从epoch0开始训练&#xff0c;因此中间要不断保存&#xff08;epoch&#xff0c;net&#xff0c;optimizer&#xff0c;scheduler&#xff09;等…

动手学深度学习——5.卷积神经网络

1.卷积神经网络特征 现在&#xff0c;我们将上述想法总结一下&#xff0c;从而帮助我们设计适合于计算机视觉的神经网络架构。 平移不变性&#xff08;translation invariance&#xff09;&#xff1a;不管检测对象出现在图像中的哪个位置&#xff0c;神经网络的前面几层应该对…

Bubbliiiing 的 Retinaface rknn python推理分析

Bubbliiiing 的 Retinaface rknn python推理分析 项目说明 使用的是Bubbliiiing的深度学习教程-Pytorch 搭建自己的Retinaface人脸检测平台的模型&#xff0c;下面是项目的Bubbliiiing视频讲解地址以及源码地址和博客地址&#xff1b; 作者的项目讲解视频&#xff1a;https:…

FFmpeg音视频流媒体的顶级项目

搞音视频、流媒体的圈子,没法躲开ffmpeg这个神级项目。 FFmpeg 是一个功能强大且广泛使用的多媒体处理工具。FFmpeg 具备众多出色的特性。它支持多种音频和视频格式的转换,能轻松将一种格式的文件转换为另一种,满足不同设备和应用的需求。不仅如此,它还可以进行视频的裁剪、…

使用多进程和多线程实现服务器并发【C语言实现】

在TCP通信过程中&#xff0c;服务器端启动之后可以同时和多个客户端建立连接&#xff0c;并进行网络通信&#xff0c;但是在一个单进程的服务器的时候&#xff0c;提供的服务器代码却不能完成这样的需求&#xff0c;先简单的看一下之前的服务器代码的处理思路&#xff0c;再来分…

手持式气象站:便携科技,掌握微观气象的利器

手持式气象站&#xff0c;顾名思义&#xff0c;是一种可以随身携带的气象监测设备。它小巧轻便&#xff0c;通常配备有温度、湿度、风速、风向、气压等多种传感器&#xff0c;能够实时测量并显示各种气象参数。不仅如此&#xff0c;它还具有数据存储、数据传输、远程控制等多种…

Django教程(003):orm操作数据库

文章目录 1 orm连接Mysql1.1 安装第三方模块1.2 ORM1.2.1、创建数据库1.2.2、Django连接数据库1.2.3、django操作表1.2.4、创建和修改表结构1.2.5、增删改查1.2.5.1 增加数据1.2.5.2 删除数据1.2.5.3 获取数据1.2.5.4 修改数据 1 orm连接Mysql Django为了使操作数据库更加简单…

Linux shell编程学习笔记65: nice命令 显示和调整进程优先级

0 前言 我们前面学习了Linux命令ps和top&#xff0c;命令的返回信息中包括优先序&#xff08;NI&#xff0c;nice&#xff09; &#xff0c;我们可以使用nice命令来设置进程优先级。 1 nice命令 的功能、格式和选项说明 1.1 nice命令 的功能 nice命令的功能是用于调整进程的…

AP ERP与汉得SRM系统集成案例(制药行业)

一、项目环境 江西某医药集团公司&#xff0c;是一家以医药产业为主营、资本经营为平台的大型民营企业集团。公司成立迄今&#xff0c;企业经营一直呈现稳健、快速发展的态势&#xff0c; 2008 年排名中国医药百强企业前 20 强&#xff0c;2009年集团总销售额约38亿元人民币…

原码、补码、反码、移码是什么?

计算机很多术语翻译成中文之后&#xff0c;不知道是译者出于什么目的&#xff0c;往往将其翻译成一个很难懂的名词。 奇怪的数学定义 下面是关于原码的“吐槽”&#xff0c;可以当作扩展。你可以不看&#xff0c;直接去下一章&#xff0c;没有任何影响。 原码的吐槽放在前面是…

配置单区域OSPF

目录 引言 一、搭建基础网络 1.1 配置网络拓扑图如下 1.2 IP地址表 二、测试每个网段都能单独连通 2.1 PC0 ping通Router1所有接口 2.2 PC1 ping通Router1所有接口 2.3 PC2 ping通Router2所有接口 2.4 PC3 ping通Router2所有接口 2.5 PC4 ping通Router3所有接口 2.…

Git仓库拆分和Merge

1. 问题背景 我们原先有一个项目叫open-api&#xff0c;后来想要做租户独立发展&#xff0c;每个租户独立成一个项目&#xff0c;比如租户akc独立部署一个akc-open-api&#xff0c;租户yhd独立部署一个yhd-open-api&#xff0c;其中大部分代码是相同的&#xff0c;少量租户定制…

2024牛客暑期多校训练营1——A,B

题解&#xff1a; 更新&#xff1a; k1的时候要乘n 代码&#xff1a; #include<bits/stdc.h> #define int long long using namespace std; const int N5e35; typedef long long ll; typedef pair<int,int> PII; int T; int n,m,mod; int fac[N][N]; int dp[N][…

笔记:Few-Shot Learning小样本分类问题 + 孪生网络 + 预训练与微调

内容摘自王老师的B站视频&#xff0c;大家还是尽量去看视频&#xff0c;老师讲的特别好&#xff0c;不到一小时的时间就缕清了小样本学习的基础知识点~Few-Shot Learning (1/3): 基本概念_哔哩哔哩_bilibili Few-Shot Learning&#xff08;小样本分类&#xff09; 假设现在每类…

【Linux】基础I/O——动静态库的制作

我想把我写的头文件和源文件给别人用 1.把源代码直接给他2.把我们的源代码想办法打包为库 1.制作静态库 1.1.制作静态库的过程 我们先看看怎么制作静态库的&#xff01; makefile 所谓制作静态库 需要将所有的.c源文件都编译为(.o)目标文件。使用ar指令将所有目标文件打包…

谷粒商城实战笔记-38-前端基础-Vue-指令-单向绑定双向绑定

文章目录 一&#xff0c;插值表达式注意事项1&#xff1a;不适合复杂的逻辑处理注意事项2&#xff1a;插值表达式支持文本拼接注意事项3&#xff1a;插值表达式只能在标签体中 二&#xff0c;v-html和v-textv-textv-html区别总结&#xff1a;最佳实践 三&#xff0c;v-model复选…

FastAPI 学习之路(五十六)将token缓存到redis

在之前的文章中&#xff0c;FastAPI 学习之路&#xff08;二十九&#xff09;使用&#xff08;哈希&#xff09;密码和 JWT Bearer 令牌的 OAuth2&#xff0c;FastAPI 学习之路&#xff08;二十八&#xff09;使用密码和 Bearer 的简单 OAuth2&#xff0c;FastAPI 学习之路&…

阵列信号处理学习笔记(二)--空域滤波基本原理

阵列信号 阵列信号处理学习笔记&#xff08;一&#xff09;–阵列信号处理定义 阵列信号处理学习笔记&#xff08;二&#xff09;–空域滤波基本原理 文章目录 阵列信号前言一、阵列信号模型1.1 信号的基本模型1.2 阵列的几何构型1.3 均匀直线阵的阵列信号基本模型 总结 前言…