【C++】二叉搜索树(手撕插入、删除、寻找)

一、什么是二叉搜索树

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

二、二叉搜索树的操作

2.1二叉搜索树的寻找

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

b、最多查找高度次,走到到空,还没找到,这个值不存在。

bool Find(const K& key)
{Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return true;}return false;}
}
2.2二叉搜索树的插入

插入的具体过程如下:

a. 树为空,则直接新增节点,赋值给root指针

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

bool Insert(const K& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//找到相同元素就报错return false;}}cur = new Node(key);if (cur->_key > curparent->_key){curparent->_right = cur;}else{curparent->_left = cur;}return true;
}
2.3二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:

  • 情况1:要删除的结点无孩子结点。

让父亲节点指向孩子节点的左节点或右节点即可(指向nullptr),该种情况可以在情况2和情况3处理

        

  • 情况2:要删除的结点只有左孩子结点。

如果删除节点是左孩子,那就让父亲节点的左指针指向删除节点的左节点,如果删除节点右孩子,那就让父亲节点的右指针指向删除节点的左节点(还要注意父亲节点不存在,及删除的是根节点的情况)

  • 情况3:要删除的结点只有右孩子结点。

如果删除节点是左孩子,那就让父亲节点的左指针指向删除节点的右节点,如果删除节点右孩子,那就让父亲节点的右指针指向删除节点的右节点

  • 况4:要删除的结点有左、右孩子结点。

找左子树的最大节点或者右子树的最小节点与删除节点的值互换(只有这两个节点满足二叉搜索树的性质),然后删除。以找右子树最小节点举例,交换值以后,让最小节点的父亲节点的左指针指向最小节点的右节点,因为右子树最小节点是最左边的节点,但他可能存在右孩子。

要注意特殊情况,右子树最小节点就是删除节点的右孩子,此时就要让父亲节点的右指针指向删除节点的右孩子

bool Erase(const K& key)
{Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//删除操作//如果删除节点左子树为空if (cur->_left == nullptr){if (_root == cur){_root = _root->_right;}else{if (curparent->_left == cur){curparent->_left = cur->_right;}else{curparent->_right = cur->_right;}}delete cur;}//如果删除节点右子树为空else if (cur->_right == nullptr){if (_root == cur){_root = _root->_left;}else{if (curparent->_left == cur){curparent->_left = cur->_left;}else{curparent->_right = cur->_left;}}delete cur;}else{//删除节点左右都不为空Node* RightMinParent = cur;Node* RightMin = cur->_right;while (RightMin->_left){RightMinParent = RightMin;RightMin = RightMin->_left;}swap(RightMin->_key, cur->_key);if (RightMinParent->_left == RightMin){RightMinParent->_left = RightMin->_right;}else{RightMinParent->_right = RightMin->_right;}delete RightMin;}return true;}}return false;
}

三、二叉搜索树的应用

K模型K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

       比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

KV模型每一个关键码key,都有与之对应的值Value,即的键值对。该种方式在现实生活中非常常见:

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对;
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是就构成一种键值对。

ps、KV模型的二叉搜索树与K模型的二叉搜索树相类似,因为KV模型的删除、寻找等操作是依靠key的与value值无关

namespace key_value
{template<class K,class V>struct BSTreeNode{BSTreeNode(const K& key,const V& value):_left(nullptr), _right(nullptr), _key(key),_value(value){}struct BSTreeNode* _left;struct BSTreeNode* _right;K _key;V _value;};template<class K,class V>class BSTree{typedef struct BSTreeNode<K,V> Node;private://销毁二叉搜索树void Destory(Node* root){//后续递归删除if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;}public:~BSTree(){Destory(_root);_root = nullptr;}bool Insert(const K& key,const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//找到相同元素就报错return false;}}cur = new Node(key,value);if (cur->_key > curparent->_key){curparent->_right = cur;}else{curparent->_left = cur;}return true;}void _Inorder(Node* ret){if (ret == nullptr)return;_Inorder(ret->_left);cout << ret->_key << ":"<<ret->_value<<endl;_Inorder(ret->_right);}void Inorder(){_Inorder(_root);cout << endl;}bool Find(const K& key){Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return true;}return false;}}bool Erase(const K& key){Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//删除操作//如果删除节点左子树为空if (cur->_left == nullptr){if (_root == cur){_root = _root->_right;}else{if (curparent->_left == cur){curparent->_left = cur->_right;}else{curparent->_right = cur->_right;}}delete cur;}//如果删除节点右子树为空else if (cur->_right == nullptr){if (_root == cur){_root = _root->_left;}else{if (curparent->_left == cur){curparent->_left = cur->_left;}else{curparent->_right = cur->_left;}}delete cur;}else{//删除节点左右都不为空Node* RightMinParent = cur;Node* RightMin = cur->_right;while (RightMin->_left){RightMinParent = RightMin;RightMin = RightMin->_left;}swap(RightMin->_key, cur->_key);if (RightMinParent->_left == RightMin){RightMinParent->_left = RightMin->_right;}else{RightMinParent->_right = RightMin->_right;}delete RightMin;}return true;}}return false;}private:Node* _root = nullptr;};void test(){BSTree<string,string> t;t.Insert("apple", "苹果");t.Insert("pear", "梨");t.Insert("pen", "笔");t.Insert("insert", "插入");t.Erase("apple");t.Erase("pen");t.Inorder();t.~BSTree();}
}

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

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

相关文章

docker部署常用工具

1.创建mysql docker run -p 3306:3306 --name mysql -v /home/mysql/conf:/etc/mysql/mysql.conf.d -v /home/mysql/log:/var/log/ -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD2022qwer -d mysql:5.7 而后再执行升级&#xff1a; docker update --restar…

二叉树习题汇总

片头 嗨&#xff01;大家好&#xff0c;今天我们来练习几道二叉树的题目来巩固知识点&#xff0c;准备好了吗&#xff1f;Ready Go ! ! ! 第一题&#xff1a;二叉树的最大深度 解答这道题&#xff0c;我们采用分治思想 1. 递归子问题&#xff1a;左子树的高度和右子树的高度 …

MQTT服务搭建及python使用示例

1、MQTT协议 1.1、MQTT介绍 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的、基于发布/订阅模式的通信协议&#xff0c;通常用于物联网设备之间的通讯。它具有低带宽、低功耗和开放性等特点&#xff0c;适合在网络带宽有限或者网络连接不稳定…

转转小程序数据处理

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872&#xff0c;x30184483x…

【25届秋招备战C++】23种设计模式

【25届秋招备战C】23种设计模式 一、简介程序员的两种思维8大设计原则 二、具体23种设计模式2.1 创建型模式2.2 结构性模式2.3 行为型模式 三、常考模式的实现四、参考 一、简介 从面向对象谈起&#xff0c; 程序员的两种思维 底层思维:向下 封装&#xff1a;隐藏内部实现 多…

FreeRTOS学习笔记-基于stm32(6)时间片调度实验

1、什么是时间片调度 在任务优先级相同的时候&#xff0c;CPU会轮流使用相同的时间去执行它&#xff0c;即时间片调度。这个相同的时间就是时间片。而时间片的大小就是SysTick的中断周期&#xff08;SysTick的中断周期可以修改&#xff09;。 比如有三个相同优先级的任务在运行…

【linux kernel】linux内核hid触摸源码hid-multitouch.c剖析

文章目录 一、内核中通用hid触摸驱动二、probe过程剖析(1)hid_parse()函数(2)hid_hw_start()函数(3)hid_connect()函数三、hid-multitouch.c应用场景一、内核中通用hid触摸驱动 在linux内核中,为HID触摸面板实现了一个通用的驱动程序,位于/drivers/hid/hid-multitouch.c文件…

在思科和华为上实现两个主机A,B A能ping通B,B不能ping通A

1.华为实验的topo如下 常规状态下任意两台主机都是可以ping通的 此时的需求是PC4能ping通PC2和PC3但是PC2和PC3不能ping通PC4 这里需要用到ACL策略 在接口上调用 验证&#xff1a; PC4能ping通PC2和PC3 PC2和PC3不能ping通PC4 2.思科类似 正常情况下是都能互相ping通 加上ac…

AI换脸原理(7)——人脸分割参考文献TernausNet: 源码解析

1、介绍 这篇论文相对来说比较简单,整体是通过使用预训练的权重来提高U-Net的性能,实现对UNet的改进。该方法也是DeepFaceLab官方使用的人脸分割方法。在介绍篇我们已经讲过了UNet的网络结构和设计,在进一步深入了解TernausNet之前,我们先简单回顾下UNet。 U-Net的主要结构…

STC8增强型单片机开发——C51版本Keil环境搭建

一、目标 了解C51版本Keil开发环境的概念和用途掌握C51版本Keil环境的安装和配置方法熟悉C51版本Keil开发环境的使用 二、准备工作 Windows 操作系统Keil C51 安装包&#xff08;可以从Keil官网下载&#xff09;一款8051单片机开发板 三、搭建流程 环境搭建的基本流程&#xf…

吴恩达2022机器学习专项课程C2(高级学习算法)W1(神经网络):2.5 更复杂的神经网络

目录 示例填写第三层的层数1.问题2.答案 公式&#xff1a;计算任意层的激活值激活函数 示例 层数有4层&#xff0c;不包括输入层。 填写第三层的层数 1.问题 你能把第二个神经元的上标和下标填写出来吗&#xff1f; 2.答案 根据公式g(wxb)&#xff0c;这里的x对应的是上…

【C语言】内存函数的概念,使用及模拟实现

Tiny Spark get dazzling some day. 目录 1. memcpy-- 函数原型-- 函数使用-- 函数的模拟实现 2.memmove-- 函数原型-- 函数使用-- 函数的模拟实现 3. memset-- 函数原型-- 函数使用-- 函数的模拟实现 4. memcmp-- 函数原型-- 函数使用-- 函数的模拟实现 1. memcpy 使用需包含…