C++二叉搜索树搜索二叉树二叉排序树

C++二叉搜索树

1. 二叉搜索树的概念

二叉搜索树BST,Binary Search Tree),也称为二叉排序树或二叉查找树。它与一般二叉树的区别在于:每个结点必须满足“左孩子大于自己,右孩子小于自己”的规则。在这种规则的约束下,二叉搜索树使用中序遍历出来的数据是一个由小到大排列的结果。

在这里插入图片描述

优点:

  1. 查找某个值最多只需要遍历高度次即可,效率高。
  2. 使用中序遍历出来的数据是有序的。

缺点:

  1. 结点的值不允许修改,否则破坏树的结构。

2. 二叉搜索树的插入

二叉搜索树的插入很简单,首先用插入的值从根结点开始比较。插入值小于结点值向左,插入值大于结点值向右,直到结点的左孩子或右孩子为空时结束,为空的位置就是插入的位置。

在这里插入图片描述

4作为插入结点的值,先找到6是插入结点的父结点,再判断4和6的大小关系,4<6,所以插入在6的左边。

在这里插入图片描述

7作为插入结点的值,先找到6是插入结点的父结点,再判断7和6的大小关系,7>6,所以插入在6的右边。

3. 二叉搜索树的删除

二叉搜索的删除需要分两种情况:

3.1 删除的结点是叶子结点

如果删除的结点是叶子结点,将该结点的父结点指针制空,再释放该结点即可。

在这里插入图片描述

3.2 删除的结点不是叶子结点

如果删除的结点不是叶子结点,可以分为三种情况讨论:

3.2.1 左子树为空

如果删除的结点的左子树为空,此时需要判断删除结点与其父子树的关系:我是父结点的左孩子,就让父结点的左指向我的右子树;我是父结点的右孩子,就让父结点的右指向我的右子树

在这里插入图片描述

在这里插入图片描述

3.2.2 右子树为空

右子树为空,原理与上相同,只是父结点改变的是左的指向。

在这里插入图片描述

在这里插入图片描述

3.2.3 左右子树不为空

如果删除结点的左右子树都不为空,那么此时就需要使用替换法的思想。替换法可以使用左子树的最大结点或右子树的最小结点作为替换结点来替换当前结点,再将替换结点删除。所谓“替换”在实际操作中不是把两个结点的值互换,而是将替换结点的值赋给原删除结点,因为替换节点最终要删除,所以不必要对其进行真正的替换操作。

使用最左结点替换:

在这里插入图片描述

使用最右结点替换:

在这里插入图片描述

4.二叉搜索树的退化问题

二叉搜索树的最优情况下,查找效率为logN。但当插入的顺序有序或部分有序时,二叉搜索树的查找效率会下降,极端情况下会退化至N

在这里插入图片描述

按{10,9,8,7,6,5,4}的顺序插入,导致二叉搜索树完全退化。

5. 参考代码

template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key,const V& value):_left(nullptr),_right(nullptr),_key(key),_value(value){}
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key, value);{if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}}Node* 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 cur;}}return nullptr;}bool Erase(const K& key){//先找到该结点Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else{//如果删除的是叶子结点,直接删除if (cur->_left == nullptr && cur->_right == nullptr){if (cur == parent->_left)parent->_left = nullptr;else if (cur == parent->_right)parent->_right = nullptr;delete cur;}//如果左为空else if (cur->_left == nullptr){if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else if (cur == parent->_right){parent->_right = cur->_right;}}delete cur;}//如果右为空else if (cur->_right == nullptr){if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else if (cur == parent->_right){parent->_right = cur->_left;}}delete cur;}// 如果左右都不为空else{//查找右子树的最左结点替换Node* RightMinParent = cur;Node* RightMin = cur->_right;while (RightMin->_left){RightMinParent = RightMin;RightMin = RightMin->_left;}cur->_key = RightMin->_key;cur->_value = RightMin->_key;cur->_value = RightMin->_value;if (RightMinParent->_left == RightMin){RightMinParent->_left = nullptr;}else{RightMinParent->_right = nullptr;}delete RightMin;}return true;}}return false;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}void InOrder(){_InOrder(_root);cout << endl;}
private:Node* _root = nullptr;
};

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

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

相关文章

AI大模型日报#0515:Google I/O大会、 Ilya官宣离职、腾讯混元文生图大模型开源

导读&#xff1a;欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”&#xff08;ERNIE 4.0&#xff09;、“零一万物”&#xff08;Yi-34B&#xff09;生成了今日要点以及每条资讯的摘要。 《AI大模型日报》今日要点&#xff1a;谷歌…

【吃透Java手写】6-Netty-NIO-BIO-简易版

Netty 1 BIO&NIO模型 1.1 BIO 在JDK1.4出来之前&#xff0c;我们建立网络连接的时候采用BIO模式&#xff0c;需要先在服务端启动一个ServerSocket&#xff0c;然后在客户端启动Socket来对服务端进行通信&#xff0c;默认情况下服务端需要对每个请求建立一堆线程等待请求&…

APP没有上架就开通了APP支付,微信商户的这个操作绝了

在当今的移动支付时代&#xff0c;APP支付已成为商家与消费者之间的重要桥梁。然而&#xff0c;对于一些尚未上架的应用来说&#xff0c;如何快速开通APP支付功能一直是个难题。最近&#xff0c;微信商户平台的一项新操作&#xff0c;为这类商家带来了福音---APP没有上架&#…

Latex问题1

问题 添加bib文件的引用后 \bibliographystyle{IEEEtran} \bibliography{IEEEabrv}之后&#xff0c;出现莫名其妙的错误&#xff0c;如下 IEEEabrv.bib是我的参考文献的bib文件&#xff0c;CCS_1.tex是我的tex文件&#xff0c;bib文件中的内容为 ARTICLE{1,author{Capponi,…

SOP for Oracle 23ai:Python 连接 Oracle 的两种方法

前情回顾 前文介绍了如何使用 python-oracledb 连接 Oracle 23ai 数据库&#xff0c;并演示了如何使用独立连接方式。 其中提到了支持两种连接池&#xff1a; DRCP 和 PRCP。 本文将对这两种连接池做具体演示。 DRCP 和 PRCP 连接池 连接池技术的优点不言而喻&#xff1a; 缩短…

P8805 [蓝桥杯 2022 国 B] 机房

P8805 [蓝桥杯 2022 国 B] 机房 分析 是一道lca题目&#xff0c;可以直接套模板 前缀和处理点权 具体思路&#xff1a; 1.n台电脑用n-1条网线相连&#xff0c;任意两个节点之间有且仅有一条路径&#xff08;拆分成各自到公共祖先节点的路径——lca&#xff09;&#xff1b;…

Docker三剑客从0到1

一、docker三剑客介绍 使用"三剑客"可以帮助我们解决docker host维护,多容器编排部署,多个docker host集群的各个难题。 docker-machine 创建虚拟机 我们知道docker使用了linux的内核技术(namespace 资源隔离,cgroup资源限制等),那么如果我想在windows或Mac系统上…

JavaScript 进阶(二)

一、深入对象 1. 创建对象的三种方式 利用 new Object 创建对象 2. 构造函数 【注意事项】 【例】 这样子写好之后&#xff0c;想要添加一个新的结构类似的对象&#xff0c;直接照着红圈中写&#xff0c;最后改相应的数据就好了 注意&#xff1a;红色是第一步&#xff0c;黄…

centos7下使用docker安装fastdfs服务

先查看容器是否已经存在 docker ps -a 删除掉之前的tracker及storage服务 docker rm tracker docker rm storage 1、没有镜像先下载镜像 docker pull morunchang/fastdfs 2、运行服务 a、不指定物理服务器路径 docker run -d --name tracker --nethost morunchang/fastdfs sh…

c++20---std::erase----std::erase_if

问题&#xff1a;如何删除满足条件的所有元素。 erase #include <iostream> #include <algorithm> #include <vector>int main(){std::vector<int> vec{1,2,3,1,1,1,1,1};std::erase(vec,1);for(int v:vec) std::cout<<v<<" "…

函数递归练习

目录 1.分析下面选择题 2.实现求第n个斐波那契数 3.编写一个函数实现n的k次方&#xff0c;使用递归实现。 4.写一个递归函数DigitSum(n)&#xff0c;输入一个非负整数&#xff0c;返回组成它的数字之和 5.递归方式实现打印一个整数的每一位 6.实现求n的阶乘 1.分析下面选择…

什么是TCP的粘包、拆包问题?

一、问题解析 TCP粘包和拆包问题是指在进行TCP通信时&#xff0c;因为TCP是面向流的&#xff0c;所以发送方在传输数据时可能会将多个小的数据包粘合在一起发送&#xff0c;而接收方则可能将这些数据包拆分成多个小的数据包进行接收&#xff0c;从而导致数据接收出现错误或者数…