BSTree二叉树讲解

二叉搜索树的概念:

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

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

二叉树的运用:(改代码就是KV模型的二叉搜索树)

1. K模型K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值。
        比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树


在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
2. KV模型每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方
式在现实生活中非常常见:
        比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文<word, chinese>就构成一种键值对;
        再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对。

二叉树的查找:

        a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
        b、最多查找高度次,走到到空,还没找到,这个值不存在。

	Node* _Find(Node* root,const K& key){if (root == nullptr)//遇到空节点就返回{return nullptr;}if (root->_kv.first == key){return root;}else if (root->_kv.first > key){_Find(root->_left, key);}else{_Find(root->_right, key);}}

 二叉搜索树的插入:

插入的具体过程如下:
        a. 树为空,则直接新增节点,赋值给root指针
        b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

	bool _Insert(const pair<K, V>& kv)//这里使用pair——key,value模型 如字典{if (_root == nullptr)//如果该二叉树的树为空 就给个节点然后返回{_root = new Node(kv);return true;}//不为空就进行寻找 找到太该呆的位置 Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}//判断该节点在父节点的左边还是右边if (parent->_kv.first > kv.first){parent->_left = new Node(kv);}else{parent->_right = new Node(kv);}}Node* _root = nullptr;
};

二叉搜索树的删除:

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
        a. 要删除的结点无孩子结点
        b. 要删除的结点只有左孩子结点
        c. 要删除的结点只有右孩子结点
        d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程
如下:
        情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
        情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
        情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点
        中,再来处理该结点的删除问题--替换法删除

	bool _Erase(Node* root, const K& key){Node* parent = nullptr;Node* cur = root;while (cur){if (cur->_kv.first == key)//如果key与要搜索的值相等 就进行删除{if (cur->_left == nullptr)//左子树为空 右子树不为空{//再考虑要删除的节点是他父节点的左子树还是右子树 将该节点接到其父节点上if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;//将该节点进行释放}else if (cur->_right == nullptr)//右子树不存在 左子树存在 同上{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}else//左右子树都存在 需要寻找一个可以代替该节点值的值 {//在左子树中找最小的值 (就是左子树最左边的那个节点)右节点就找右子树中最大的节点 (就是右子树最右边的那个节点)Node* parent1 = nullptr;Node* tmp = cur;while (tmp->_left)//寻找左节点{parent1 = tmp;tmp = tmp->_left;}swap(&cur->_kv, &tmp->_kv);//找到进行值的交换parent1->_left = tmp->_right;//如果最小的左节点的左子树为空右子树不为空 将右子树接到该节点的父亲上 但是如果右子树为空 也可以将空节点接到其父节点上 不产生影响delete tmp;//释放节点}}else{if (root->_kv.first > key){parent = cur;cur = cur->_left;}else{parent = cur;cur = cur->_right;}}}}

二叉树的遍历:(中序遍历)(将二叉树中key的值按顺序打印)

	void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " " << root->_kv.second << endl;_InOrder(root->_right);}

以下就是二叉搜索树的完整代码 以及对应的测试用例,可以自行去调用测试。

#include<iostream>
#include<string>
using namespace std;template<class K,class V>
struct BSTreeNode
{typedef BSTreeNode<K, V> Node;BSTreeNode(const pair<K, V>& x):_kv(x), _left(nullptr), _right(nullptr){}pair<K, V> _kv;Node* _left;Node* _right;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:bool Insert(const K& key, const V& value){pair<K, V> kv(key, value);return _Insert(kv);}Node* Find(const K& key){return _Find(_root,key);}bool Erase(const K& key){return _Erase(_root, key);}void InOrder(){_InOrder(_root);}
private:bool _Erase(Node* root, const K& key){Node* parent = nullptr;Node* cur = root;while (cur){if (cur->_kv.first == key){if (cur->_left == nullptr){if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;}else if (cur->_right == nullptr){if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}else{Node* parent1 = nullptr;Node* tmp = cur;while (tmp->_left){parent1 = tmp;tmp = tmp->_left;}swap(&cur->_kv, &tmp->_kv);parent1->_left = tmp->_right;delete tmp;}}else{if (root->_kv.first > key){parent = cur;cur = cur->_left;}else{parent = cur;cur = cur->_right;}}}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " " << root->_kv.second << endl;_InOrder(root->_right);}Node* _Find(Node* root,const K& key){if (root == nullptr){return nullptr;}if (root->_kv.first == key){return root;}else if (root->_kv.first > key){_Find(root->_left, key);}else{_Find(root->_right, key);}}bool _Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}if (parent->_kv.first > kv.first){parent->_left = new Node(kv);}else{parent->_right = new Node(kv);}}Node* _root = nullptr;
};void TestBSTree()
{BSTree<string, string> dict;dict.Insert("insert", "插入");dict.Insert("erase", "删除");dict.Insert("left", "左边");dict.Insert("string", "字符串");string str;while (cin >> str){auto ret = dict.Find(str);if (ret){cout << str << ":" << ret->_kv.second << endl;}else{cout << "单词拼写错误" << endl;}}string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };// 统计水果出现的次BSTree<string, int> countTree;for (auto str : strs){auto ret = countTree.Find(str);if (ret == NULL){countTree.Insert(str, 1);}else{ret->_kv.second++;}}countTree.InOrder();
}

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

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

相关文章

YOLOv5— Fruit Detection

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营-第7周&#xff1a;咖啡豆识别&#xff08;训练营内部成员可读&#xff09; &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https…

CentOS 安装 tomcat 并设置 开机自启动

CentOS 安装 tomcat 并设置 开机自启动 下载jdk和tomcat curl https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.tar.gz curl https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.15/bin/apache-tomcat-10.1.15.tar.gz解压jdk和tomcat并修改目录名称 tar -z…

homeassistant安装HACS应用商店

环境&#xff1a;iStoreOS&#xff0c;已在商店中安装homeassistant。 homeassistant在iStoreOS中是以docker容器运行的。 1、进入终端&#xff0c;输入账号和密码&#xff08;默认&#xff1a;root&#xff0c;password&#xff09; 查看容器&#xff1a;docker ps 进入容…

3.3每日一题(变量可分离方程)

1、判断类型选方法&#xff1a;等式中分别提一个x、y出来&#xff0c;形成了x与y相乘的等式&#xff1b;为变量可分离类型 2、不一定非得把y解出来&#xff0c;化成上述的等式即可&#xff08;为隐函数的方程解&#xff09; 注&#xff1a;等式不定积分后记得&#xff0b;一个…

大数据-Storm流式框架(七)---Storm事务

storm 事务 需求 storm 对于保证消息处理&#xff0c;提供了最少一次的处理保证。最常见的问题是如果元组可以被 重发&#xff0c;可以用于计数吗&#xff1f;不会重复计数吗&#xff1f; strom0.7.0 引入了事务性拓扑的概念&#xff0c;可以保证消息仅被严格的处理一次。因此可…

【电路笔记】-交流电感和感抗

交流电感和感抗 文章目录 交流电感和感抗1、概述1.1 电感1.2 电感器 2、频率特性2.1 电抗(Reactance)2.2 相移2.3 感应现象 3、RL滤波器4、总结 在之前有 交流电阻的文章中&#xff0c;我们已经看到电阻器在正常频率下的直流或交流状态下的行为是相同的。 然而&#xff0c;其他…

【机器学习合集】人脸表情分类任务Pytorch实现TensorBoardX的使用 ->(个人学习记录笔记)

人脸表情分类任务 注意&#xff1a;整个项目来自阿里云天池&#xff0c;下面是开发人员的联系方式&#xff0c;本人仅作为学习记录&#xff01;&#xff01;&#xff01;该文章原因&#xff0c;学习该项目&#xff0c;完善注释内容&#xff0c;针对新版本的Pytorch进行部分代码…

山东大学开发可解释深度学习算法 RetroExplainer,4 步识别有机物的逆合成路线

逆合成旨在找到一系列合适的反应物&#xff0c;以高效合成目标产物。这是解决有机合成路线的重要方法&#xff0c;也是有机合成路线设计的最简单、最基本的方法。 早期的逆合成研究多依赖编程&#xff0c;随后这一工作被 AI 接替。然而&#xff0c;现有的逆合成方法多关注单步逆…

机器学习第一周

一、概述 机器学习大致会被划分为两类&#xff1a;监督学习&#xff0c;无监督学习 1.1 监督学习 监督学习其实就是&#xff0c;给计算机一些输入x和正确的输出y&#xff08;训练数据集&#xff09;&#xff0c;让他总结x->y的映射关系&#xff0c;从而给他其他的输入x&a…

【算法】动态规划之LeetCode 53.最大子数组和

目录 文章目录 **目录**&#x1f4d1;前言1.题目描述2. 动态规划法 &#x1f4d1;文章末尾 &#x1f4d1;前言 本文主要是leetcode题解析&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁…

ThreadLocal 会出现内存泄漏吗?

ThreadLocal ThreadLocal 是一个用来解决线程安全性问题的工具。它相当于让每个线程都开辟一块内存空间&#xff0c;用来存储共享变量的副本。然后每个线程只需要访问和操作自己的共享变量副本即可&#xff0c;从而避免多线程竞争同一个共享资源。它的工作原理很简单&#xff0…

基于Ubuntu20.04安装ROS系统

文章目录 一、ROS简介二、ROS安装三、ROS安装测试四、安装问题解决1. sudo rosdepc init&#xff1a;找不到命令2. ERROR: cannot download default sources list from...3. Command roscore not found...4. Resource not found: roslaunch... 一、ROS简介 ROS是用于编写机器人…

[ubuntu系统下的文本编辑器nano,vim,gedit,文件使用,以及版本更新问题]

文本编辑器概要 在Ubuntu系统下&#xff0c;有许多文本编辑器可供选择&#xff0c;每个编辑器都有其独特的特性和用途。以下是一些常见的文本编辑器&#xff1a; Gedit&#xff1a; 这是Ubuntu默认的文本编辑器&#xff0c;它简单易用&#xff0c;适合基本的文本编辑任务。 安…

取石子

每一堆数量都>1的话可以把合并操作和取石子看成一种操作&#xff0c;总操作数就是sumn-1&#xff0c;为奇数就是Alice先手必胜&#xff0c;哪怕有一堆是2&#xff0c;Bob取后变为1&#xff0c;Alice也可以通过合并操作让1变成>1的数 可以分成两大板块a、b, a中方石子个数…

haproxy高可用集群

高可用集群 Haproxy &#xff1a;他是常用的负载均衡软件 Nginx 支持四层转发&#xff0c;和七层转发 Haproxy 也可以四层和七层转发 LVS的DR发和nat是基于四层还是七层的转&#xff1f; 都基于是四层转发&#xff08…

[SHCTF 2023 校外赛道] pwn

有19道题这么多,不过基本是入门题,都是在骗新生,看这么容易快来PWN吧! week1 四则计算器 这里用危险函数gets读入有个溢出.而且PIE也没开,地址是固定的.而且有后门.直接溢出到ret写上后门即可. from pwn import *p remote(112.6.51.212, 31473) context(archamd64, log_lev…

#stm32整理(二)关于MDK的编译过程及文件类型全解

参考野火开发指南如有侵权即刻删除&#xff0c;只是为了学习交流使用 1、编译 1、编译过程简介 (1&#xff09;编译&#xff0c;MDK 软件使用的编译器是 armcc 和 armasm&#xff0c;它们根据每个 c/c 和汇编源文件编译 成对应的以“.o”为后缀名的对象文件 (Object Code&…

修改el-date-picker宽度

<div style"width: 100%"><el-date-pickerstyle"width:100%"v-model"value"type"datetimerange"start-placeholder"开始日期"end-placeholder"结束日期":default-time"[12:00:00]"value-forma…

Redis队列Stream

1 缘起 项目中处理文件的场景&#xff1a; 将文件处理请求放入队列&#xff0c; 一方面&#xff0c;缓解服务器文件处理压力&#xff1b; 另一方面&#xff0c;可以根据文件大小拆分到不同的队列&#xff0c;提高文件处理效率。 这是Java开发组Leader佳汇提出的文件处理方案&a…