当前位置: 首页 > news >正文

[C++]二叉搜索树

一、定义

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

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

二、插入insert

对于二叉搜索树的插入操作,我们将需要插入的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。走到空结点的时候,那么这个位置就是这个key值的归宿。

template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* left;BSTreeNode<K, V>* right;K _key;V _value;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:BSTree(){_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node;_root->_key = key;_root->_value = value;_root->left = nullptr;_root->right = nullptr;}else{Node* cur = _root;Node* parent = _root;while (cur){if (key < cur->_key){parent = cur;cur = cur->left;}else if (key > cur->_key){parent = cur;cur = cur->right;}}cur = new Node;cur->left = nullptr;cur->right = nullptr;cur->_key = key;cur->_value = value;if (key < parent->_key){parent->left = cur;}else{parent->right = cur;}}return true;}
private:Node* _root = nullptr;
};

三、查找操作find

对于二叉搜索树的查找操作,我们将需要查找的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。

若走到空,则说明没有这个值,返回空指针。若找到该值,则返回该值的结点。

	Node* Find(const K& key){Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->left;}else if (key > cur->_key){cur = cur->right;}else{return cur;}}return nullptr;}

四、删除操作

	bool Erase(const K& key){Node* cur = _root;Node* parent = _root;while (cur){//若key小于当前结点的值,则往左子树走if (key < cur->_key){parent = cur;cur = cur->left;}//若key大于当前结点的值,则往右子树走else if (key > cur->_key){parent = cur;cur = cur->right;}//若key值与当前结点的值相等,则说明该结点就是需要删除的else{//该结点左右子树皆为空的情况if (cur->left == nullptr && cur->right == nullptr){//直接删除if (key < parent->_key){parent->left = nullptr;}if (key > parent->_key){parent->right = nullptr;}delete cur;}//该结点左子树为空的情况else if (cur->left == nullptr){//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->right;elseparent->right = cur->right;delete cur;}//该结点右子树为空的情况else if (cur->right == nullptr){//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->left;elseparent->right = cur->left;delete cur;}//左右子树皆不为空//该情况下,我们需要找到左子树的最大结点/右子树的最小结点//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换//此时我们只需要删除交换之后值为需要删除的数值的结点//这里以与左子树的最大结点交换为例else{//del是之后需要删除的结点Node* del = cur->left;//tmp是需要删除的结点的父结点Node* tmp = del;//找到左子树的最大结点,记录为del,此时tmp为del的父结点while (del->right){tmp = del;del = del->right;}//交换key值swap(cur->_key, del->_key);//如即将被删除的结点有左子树,则将其链接到tmp上if (del->left){tmp->right = del->left;}//否则直接将tmp指向即将被删除的结点的指针置空else{tmp->right = nullptr;}//删除交换key值后的结点delete del;}return true;}}return false;}

五、中序遍历InOrder

使用中序遍历二叉搜索树时,我们得到的是一个递增序列。

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

六、完整代码

#include<iostream>
#include<string>template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* left;BSTreeNode<K, V>* right;K _key;V _value;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:BSTree(){_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node;_root->_key = key;_root->_value = value;_root->left = nullptr;_root->right = nullptr;}else{Node* cur = _root;Node* parent = _root;while (cur){if (key < cur->_key){parent = cur;cur = cur->left;}else if (key > cur->_key){parent = cur;cur = cur->right;}}cur = new Node;cur->left = nullptr;cur->right = nullptr;cur->_key = key;cur->_value = value;if (key < parent->_key){parent->left = cur;}else{parent->right = cur;}}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->left;}else if (key > cur->_key){cur = cur->right;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* cur = _root;Node* parent = _root;while (cur){//若key小于当前结点的值,则往左子树走if (key < cur->_key){parent = cur;cur = cur->left;}//若key大于当前结点的值,则往右子树走else if (key > cur->_key){parent = cur;cur = cur->right;}//若key值与当前结点的值相等,则说明该结点就是需要删除的else{//该结点左右子树皆为空的情况if (cur->left == nullptr && cur->right == nullptr){//直接删除if (key < parent->_key){parent->left = nullptr;}if (key > parent->_key){parent->right = nullptr;}delete cur;}//该结点左子树为空的情况else if (cur->left == nullptr){//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->right;elseparent->right = cur->right;delete cur;}//该结点右子树为空的情况else if (cur->right == nullptr){//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->left;elseparent->right = cur->left;delete cur;}//左右子树皆不为空//该情况下,我们需要找到左子树的最大结点/右子树的最小结点//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换//此时我们只需要删除交换之后值为需要删除的数值的结点//这里以与左子树的最大结点交换为例else{//del是之后需要删除的结点Node* del = cur->left;//tmp是需要删除的结点的父结点Node* tmp = del;//找到左子树的最大结点,记录为del,此时tmp为del的父结点while (del->right){tmp = del;del = del->right;}//交换key值swap(cur->_key, del->_key);//如即将被删除的结点有左子树,则将其链接到tmp上if (del->left){tmp->right = del->left;}//否则直接将tmp指向即将被删除的结点的指针置空else{tmp->right = nullptr;}//删除交换key值后的结点delete del;}return true;}}return false;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->left);cout << root->_key << ' ';_InOrder(root->right);}void InOrder(){_InOrder(_root);cout << endl;}private:Node* _root = nullptr;
};

相关文章:

  • 78MXX——线性稳压器电路,用于各种电视机、收录机、电子仪器、设备的稳压电源上,内置短路保护电路,热保护电路
  • C语言学习day16:二维数组
  • C++初阶(十一) list
  • Python算法题集_二叉树的右视图
  • 分布式学习笔记
  • notepad++运行python闪一下就没啦
  • 跟着pink老师前端入门教程(JavaScript)-day03
  • 嵌入式大厂面试题(1)—— CVTE
  • 【测试运维】性能测试经验文档总结第3篇:VuGen详解(已分享,附代码)
  • java面试微服务篇
  • 21种matlab信号分解方法汇总
  • 【Mysql】数据库架构学习合集
  • 探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’
  • 黑客利用F5 BIG-IP漏洞传播Linux挖矿病毒
  • Python如何实现定时发送qq消息
  • ----------
  • Google 是如何开发 Web 框架的
  • [case10]使用RSQL实现端到端的动态查询
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • Angular 响应式表单 基础例子
  • Apache的80端口被占用以及访问时报错403
  • Asm.js的简单介绍
  • HTTP那些事
  • JavaScript 基本功--面试宝典
  • LeetCode29.两数相除 JavaScript
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • npx命令介绍
  • React-Native - 收藏集 - 掘金
  • Vim Clutch | 面向脚踏板编程……
  • VUE es6技巧写法(持续更新中~~~)
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 关于使用markdown的方法(引自CSDN教程)
  • 计算机在识别图像时“看到”了什么?
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 深度解析利用ES6进行Promise封装总结
  • 手写双向链表LinkedList的几个常用功能
  • 温故知新之javascript面向对象
  • 小程序button引导用户授权
  • Java性能优化之JVM GC(垃圾回收机制)
  • 说说我为什么看好Spring Cloud Alibaba
  • ​iOS实时查看App运行日志
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • #pragam once 和 #ifndef 预编译头
  • $.ajax()方法详解
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (二)PySpark3:SparkSQL编程
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十一)JAVA springboot ssm b2b2c多用户商城系统源码:服务网关Zuul高级篇
  • (五)网络优化与超参数选择--九五小庞
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (一)u-boot-nand.bin的下载