【C++课程学习】:二叉搜索树

ops/2024/11/16 22:27:05/

🎁个人主页:我们的五年

🔍系列专栏:C++课程学习

🎉欢迎大家点赞👍评论📝收藏⭐文章

目录

二叉树搜索树的概念:

节点的结构:

⚽️结构:

⚽️ 构造函数:

搜索二叉树的查找:

⛳️查找步骤:

⛳️时间复杂度:

⛳️代码实现:

搜索二叉树的插入:

🌴插入步骤:

🌴插入代码:

二叉树的删除:

🍁删除步骤:

●叶子节点(左右指针都为空):

●只有一个孩子(左子树为空,或者右子树为空):

●有两个孩子:

🍁实现代码:

拷贝构造,析构函数:

搜索二叉树的应用:


 

二叉树搜索树的概念:

 二叉搜索树也叫二叉排序树二叉查找树

二叉搜索树可以为空,但是不为空的时候,具有下面的性质

●非空左子树的所有键值小于根的键值。

●非空右子树的所有键值大于根的键值。

●左右子树任然是搜索二叉树。

节点的结构:

⚽️结构:

因为搜索二叉树也是二叉树,要定义左右两个节点指针。此时先以K树讲解。此时的节点结构为:

⚽️ 构造函数:

在实践情况中,我们一般用一个T类型的值(键值)去进行构造一个节点。其他的用BST_node去进行拷贝构造基本是不可能的。所以写这一个构造函数就够了。

struct BST_Node {//用key值进行构造BST_Node(const T& key=T()):_left(nullptr),_right(nullptr),_key(key){}//左右节点指针,以及键值BST_Node<T>* _left;BST_Node<T>* _right;T _key;
};

另外下面还有对该节点和节点指针重命名的。 

    typedef BST_Node<T> node;
    typedef node* pnode;

搜索二叉树的查找:

⛳️查找步骤:

如果要查找一个值,根据二插树的性质。从根节点开始,如果根的键值不是,那么如果要查找的键值大于根,就往右子树走。如果小于根的键值,那么就往左子树走。如果走到空了,还没找到,那么这个值就不存在。

⛳️时间复杂度:

最坏情况是查找树的高度次。

但是此时不是满二叉树,不能认为现在的二叉树的高度为(logN)+1。

最坏二叉树的高度为N,所以查找就是N次。时间复杂度就是O(N)。

⛳️代码实现:

	bool find(T& key){pnode p=_root;while (p){if (key < _root->_key)p = p->_left;else if (key > _root->_key)p = p->_right;elsereturn true;}return false;}

搜索二叉树的插入:

🌴插入步骤:

根据搜索二叉树的规则,如果要插入的值小于此时的键值,那么就往左边走,如果大于此时的键值就往右走。直到走到空为止,然后用一个键值为key的新节点插入到搜索二叉树中。要插入,就要知道父节点,所以在走的过程中,要用parent_cur时刻记录cur的父节点。

因为当_root为空时进行了特判,所以parent_cur不可能为nullptr,所以不会发生对野指针的解引用。

🌴插入代码:

	bool insert(const T& key){//当根节点为nullptr时,直接向_root插入节点if (_root == nullptr){_root = new node(key);return true;}//_root为二叉搜索树的根节点pnode cur = _root;pnode parent_cur = nullptr;while (cur){//如果要插入的值小于此时的根节点,就往左边走if (key < cur->_key){parent_cur = cur;cur = cur->_left;}//如果要插入的值大于此时的根节点,就往右边走else if (key > cur->_key){parent_cur = cur;cur = cur->_right;}//此时表示二叉树中存在该值,就返回falseelsereturn false;}//申请节点,cur在parent_cur的左边就把新节点插入parent_cur的左边,如果不是就插入右边pnode newnode = new node(key);if (key< parent_cur->_key)parent_cur->_left = newnode;elseparent_cur->_right = newnode;return true;}

二叉树的删除:

🍁删除步骤:

把搜索二叉树的节点进行分类,具体点可以分为三种情况:

●叶子节点(左右指针都为空):

删除叶子节点时,直接删除即可,如果叶子节点在父节点的左边,就把父节点的左指针变为空,如果叶子节点在父节点的右边,就把父节点的右指针变为nullptr。

注意:如果此时叶子节点为_root(根节点),就没有父节点,只需把_root变为nullptr。

只有一个孩子(左子树为空,或者右子树为空):

要删除这样的节点也是比较简单的,只需要把该节点的孩子给父节点就可以。叶子节点也可以当成这种情况进行处理。

同样也应该注意该节点是不是根(_root)节点。

●有两个孩子:

这种情况,就不能直接把两个孩子都给父亲,因为一个节点最多有两个孩子,如果父节点已经有一个孩子了,就不能把要删除的节点两个孩子给父节点了。

所以我们就需要去找一个节点来带这两个孩子。要找的这个节点要有这样的性质:

●如果删除的节点在父节点左边,那么找到的新节点就要比父节点小。相反就比父节点大。

解决办法:

就在要删除的这棵树中找,就满足这样的性质。

下面图中在绿色这棵树中找,全部满足键值大于根节点5。

●新的节点必须比左树所有节点都大比右树都小

解决办法:

1.左树的节点都比根的键值小,那就比所有右树节点小。左树所有节点都满足了比右树都小。

2.在左树中找到最大就满足了左树节点都小于这个节点。从左树开始,一直往右边走,就可以满足这三个性质。

上图的键值为7的节点。

🍁实现代码:

	bool erase(const T& key){pnode parent_cur = nullptr;pnode cur = _root;//寻找键值为key的节点while (cur){if (key < cur->_key){parent_cur = cur;cur = cur->_left;}else if (key > cur->_key){parent_cur = cur;cur = cur->_right;}elsebreak;	//找到了}if(cur==nullptr)return false;//只有右孩子,叶子节点可以当成这种情况处理if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (parent_cur->_left == cur)parent_cur->_left = cur->_right;elseparent_cur->_right = cur->_right;}delete cur;return true;}//只有左孩子else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (parent_cur->_left == cur)parent_cur->_left = cur->_left;elseparent_cur->_right = cur->_left;}delete cur;return true;}//有两个孩子else{pnode left_max_parent = cur;pnode left_max = cur->_right;while (left_max->_right){left_max_parent = left_max;left_max = left_max->_right;}cur->_key = left_max->_key;if (left_max == left_max_parent->_left)left_max_parent->_left=left_max->_left;elseleft_max_parent->_right=left_max->_left;delete left_max;return true;}}

拷贝构造,析构函数:

进行深拷贝,从_root开始遍历,进行深拷贝。

析构函数也要进行逐一释放。

	BST(const BST<T>& t){_root = copy(t._root);}pnode copy(pnode root){if (root == nullptr)return root;pnode newnode = new node;newnode->_key = root->_key;newnode->_left = copy(root->_left);newnode->_right = copy(root->_right);return newnode;}~BST(){Destroy(_root);}void Destroy(pnode root){if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;}

搜索二叉树的应用:

K模型:

上面所说的是K模型,在插入一些数以后,可以去查找某个值在不在这棵树中。例如:查找一个单词是否正确,就可以去一棵有所以单词的搜索二叉树中寻找在不在树中。

KV模型:

就是一个Key值,会与一个value值对应,找到了key值,就可以得到value值。

例如:英汉字典,每个单词就可以对应一个中文意思,找到了key(英文)就可以得到value(中文)。


这种二叉树有极端情况:

使得它的时间复杂度为O(N)。


http://www.ppmy.cn/ops/134251.html

相关文章

Rust 整数

表1 整数类型 大小&#xff08;位&#xff09;有符号整数无符号整数8i8u816i16u1632i32u3264i64u64128i128u128机器字isizeusize 表2 整数字面量 序号说明案例1可以在整数任意位置添加下划线_1234_5678、1_2_3_4_5_6_7_8、12_345_678 都合法的整数&#xff0c;都表示数12345…

Linux探秘坊-------1.系统核心的低语:基础指令的奥秘解析(1)

1.Linux的背景介绍 Linux 操作系统的发展历程充满了激情与创新喵&#xff5e;&#x1f380; 萌芽期 (1983 - 1991)&#xff1a;Linux 的历史可追溯到 1983 年&#xff0c;理查德斯托曼 (Richard Stallman) 发起 GNU 计划&#xff0c;目标是创建一个自由软件操作系统。1987 年发…

Prometheus面试内容整理-Metrics 类型

在 Prometheus 中,指标(Metrics)是核心数据单位,用于描述系统的各种状态和性能指标。Prometheus 将这些指标分为四种主要类型,每种类型适用于不同的监控场景。理解这四种指标类型有助于我们准确采集、分析和理解监控数据。 Counter(计数器) 1. 概念: Counter 是一种只…

01 最舒适的python开发环境

0 前言 我自己经过尝试&#xff0c;总结出python3开发环境的最舒适方式。 python3安装创建虚拟环境 venvjupyter notebook 笔记本安装vscode插件(Python, Pylance, Jupyter) 1 python3安装 ubuntu系统下安装最新版本的python3 sudo apt update sudo apt install python32 …

cooladmin 后端 查询记录

查询记录&#xff1a;pageQueryOp中列表查询的group by node ts controller代码如下 import { CoolController, BaseController } from cool-midway/core; import { Inject, Post, Get, Param } from midwayjs/decorator; import { ComparePricesPlanInfoEntity } from ../../…

华为云前台用户可挂载数据盘和系统盘是怎么做到的?

用户可以选择磁盘类型和容量&#xff0c;其后台是管理员对接存储设备 1.管理员如何在后台对接存储设备&#xff08;特指业务存储&#xff09; 1.1FusionSphere CPS&#xff08;Cloud Provisionivice&#xff09;云装配服务 它是first node https://10.200.4.159:8890 对接存…

linux安装好用的第三方中文输入法

第三方输入法比自带的ibus好用多了&#xff0c;总体评价就是顺畅。 首先&#xff0c;第一步&#xff0c;看你系统你目前使用的是哪种输入法平台 在设置 -> 区域与语言 -> 管理已安装的语言 -> 键盘输入法系统 查看。 如果是ibus&#xff0c;就安装ibus-rime, 命令 s…

Linux 命令行配置为单臂旁路由。

准备&#xff1a; sudo nano /etc/sysctl.conf net.ipv4.ip_forward1 sudo sysctl -p 方法一&#xff1a;&#xff08;NATFORWARD&#xff09; en0 为单臂路由网卡 注意&#xff1a;都可以增加来源限定 # 设置NAT规则 sudo iptables -t nat -A POSTROUTING -o en0 -j MASQ…