数据结构:二叉搜索树

目录

1、二叉搜索树概念

2、 二叉搜索树的插入

3、二叉搜索树的查找

4、二叉搜索树的删除

5、二叉搜索树的中序遍历

实现


1、二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一棵空树 ,或者是具有以下性质的二叉树 :
  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

 定义一个二叉搜索树类

template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
private:Node* _root = nullptr;
public:bool Insert(const K& key);            //插入bool Find(const K& key);              //查找bool Erase(const K& key);             //删除void InOrder();                       //中序遍历void _InOrder(Node* root);};

2、 二叉搜索树的插入

  • 树为空,则直接新增节点,赋值给root指针
  • 树不空,按二叉搜索树性质查找插入位置,插入新节点

template<class K>
bool BSTree<K>::Insert(const K& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur != nullptr){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;       //cur->_key == key}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;
}

3、二叉搜索树的查找

  • 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
  • 最多查找高度次,走到到空,还没找到,这个值不存在。
template<class K>
bool BSTree<K>::Find(const K& key)
{Node* cur = _root;while (cur != nullptr){if (key < cur->_key)      //key小于cur->_key,cur向左走{cur = cur->_left;}else if (key > cur->_key)   //key大于于cur->_key,cur向右走{cur = cur->_right;}else                       //key等于于cur->_key,返回true{return true;}}return false;                 //不存在返回false}

4、二叉搜索树的删除

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

 替换法删除:我们可以使用被删的节点的左子树的最大节点或者右子树的最小节点,来替代被删的节点的值

template<class K>
bool BSTree<K>::Erase(const K& key)
{Node* parent = nullptr;Node* cur = _root;while (cur != nullptr){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else                             //找到要删除的数{// 准备删除//分为三种情况//1、左为空//2、右为空//3、左右都不为空  if (cur->_left == nullptr)   //左为空{if (cur == _root)      //1、要删除的点为根节点{_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr)   //右为空{if (cur == _root)             //1、要删除的点为根节点{_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else                     //左右都不为空{//我们可以使用被删的节点的左子树的最大节点或者右子树的最小节点,//来替代被删的节点的值Node* parent = cur;Node* subLeft = cur->_right;while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;    // 右子树的最小节点(最左节点)}swap(cur->_key, subLeft->_key);  //右子树的最小节点与被删节点的值交换if (subLeft == parent->_left){parent->_left = subLeft->_right;}else{parent->_right = subLeft->_right;}}return true;}}return false;         //没有找到要删除的数
}

5、二叉搜索树的中序遍历

根据二叉搜索树的特性,我们可以推出二叉搜索树的中序遍历是一个有序的数据

我们可以采用递归的方法去遍历

template<class K>
void BSTree<K>::InOrder()
{_InOrder(_root);cout << endl;
}
template<class K>
void BSTree<K>::_InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}

实现

template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}
};template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
private:Node* _root = nullptr;
public:bool Insert(const K& key);            //插入bool Find(const K& key);              //查找bool Erase(const K& key);             //删除void InOrder();                       //中序遍历void _InOrder(Node* root);};template<class K>
bool BSTree<K>::Insert(const K& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur != nullptr){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;       //cur->_key == key}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;
}template<class K>
bool BSTree<K>::Find(const K& key)
{Node* cur = _root;while (cur != nullptr){if (key < cur->_key)      //key小于cur->_key,cur向左走{cur = cur->_left;}else if (key > cur->_key)   //key大于于cur->_key,cur向右走{cur = cur->_right;}else                       //key等于于cur->_key,返回true{return true;}}return false;                 //不存在返回false}template<class K>
bool BSTree<K>::Erase(const K& key)
{Node* parent = nullptr;Node* cur = _root;while (cur != nullptr){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{// 准备删除  if (cur->_left == nullptr)   //左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr)   //右为空{if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else{//左右都不为空// 右树的最小节点(最左节点)Node* parent = cur;Node* subLeft = cur->_right;while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left)parent->_left = subLeft->_right;elseparent->_right = subLeft->_right;}return true;}}return false;
}
template<class K>
void BSTree<K>::InOrder()
{_InOrder(_root);cout << endl;
}
template<class K>
void BSTree<K>::_InOrder(Node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}

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

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

相关文章

Python第三方库 - Flask(python web框架)

1 Flask 1.1 认识Flask Web Application Framework&#xff08; Web 应用程序框架&#xff09;或简单的 Web Framework&#xff08; Web 框架&#xff09;表示一个库和模块的集合&#xff0c;使 Web 应用程序开发人员能够编写应用程序&#xff0c;而不必担心协议&#xff0c;线…

定档11月2日,YashanDB 2023年度发布会即将启航

数据库作为支撑核心业务的关键技术&#xff0c;对数字经济的发展有着重要的支撑作用&#xff0c;随着云计算、AI等技术的迅猛发展和数据量的爆发式增长&#xff0c;推动着数据库技术的加速创新。 为了应对用户日益复杂的数据管理需求&#xff0c;赋能行业国产化建设和数字化转型…

华为OD 题目汇总 Java【A卷+B卷】2023

华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 华为机试有三道题目,整体难度基本就是力扣中等或简单题,前两道分值为100分,第三道分值为200分。总分为400分…

unity 一键替换 UI上所有字体,批量替换字体(包括:Text和Text (TMP))

前言&#xff1a;在开发中会遇到这种情况&#xff0c;开发完了&#xff0c;发现UI字体没有替换&#xff0c;特别是需要发布到WebGL端的同学&#xff0c;突然发现无法显示汉字了。下面一个非常方便的方法完美解决。 1.解压出来的脚本放在Edit文件下&#xff0c;没有的创建一个 2…

Android 中的 本地广播LocalBroadcastManager

Android 中的 本地广播LocalBroadcastManager 文章目录 Android 中的 本地广播LocalBroadcastManager一、LocalBroadcastManager 的基本作用二 、LocalBroadcastManager 的基本使用1、包的导入&#xff08;1&#xff09;Android 源码中bp文件的导入&#xff1a;&#xff08;2&a…

2016年亚太杯APMCM数学建模大赛A题基于光学信息数据的温度及关键元素含量预测求解全过程文档及程序

2016年亚太杯APMCM数学建模大赛 A题 基于光学信息数据的温度及关键元素含量预测 原题再现 光含有能量&#xff0c;在一定条件下可以转化为热。燃烧是一种常见的现象&#xff0c;既能发光又能发热。光和热通常是同时存在的&#xff0c;一般来说&#xff0c;光强度越高&#xf…

2023年香水行业数据分析:国人用香需求升级,高端香水高速增长

在人口结构变迁的背景下&#xff0c;“Z世代”作为当下我国的消费主力&#xff0c;正在将“悦己”消费推动成为新潮流。具备经济基础的“Z世代”倡导“高颜值”、“个性化”、“精致主义”&#xff0c;这和香水、香氛为代表的“嗅觉经济”的特性充分契合&#xff0c;因此&#…

mysql中limit和offset的用法详细介绍

有的时候我们在学习或者工作中会使用到SQL语句&#xff0c;那么介绍一下limit和offset的使用方法。 mysql里分页一般用limit来实现&#xff0c;例如&#xff1a; 1、select* from user limit 3 表示直接取前三条数据 2、select * from user limit 1,3; 表示取1后面的第2,3,…

翻页视图ViewPager

ViewPager控件允许页面在水平方向左右滑动&#xff0c;就像翻书、翻报纸&#xff0c;Android提供了已经分装好的控件。对于ViewPager来说&#xff0c;一个页面就是一个项&#xff08;相当于ListView的一个列表项&#xff09;&#xff0c;许多页面组成ViewPager的页面项。 List…

【计算机网络笔记】网络应用对传输服务的需求

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

LuatOS-SOC接口文档(air780E)--log - 日志库

常量 常量 类型 解释 log.LOG_SILENT number 无日志模式 log.LOG_DEBUG number debug日志模式 log.LOG_INFO number info日志模式 log.LOG_WARN number warning日志模式 log.LOG_ERROR number error日志模式 log.setLevel(level) 设置日志级别 参数 传入值…

实现打包后暴露可修改接口地址文件

### vue-cli3 实现打包后暴露可修改接口地址文件 在前后端分离的开发模式中,有时候我们开发好打包的文件在部署完之后,需要去修改获取接口的地址,这个时候就需要前端修改完之后重新打包再部署了,但是如果我们只是需要修改接口地址时,反复的重新打包就太麻烦了,接下来就分享一种…

Rust笔记【1】

元组和解构语法 let tup : (i32, f64, u8) (666, 2.0, 1);let tup (666, 2.0, 1); let (x, y, z) tup;let x tup.0; let y tup.1; let z tup.2;数组类型 数组定义是方括号&#xff1a;[ ] 元组定义是小圆括号&#xff1a;( ) 结构体定义是大括号&#xff1a;{ }&#xf…

USB学习(2):USB端点和传输协议(数据包、事物)详解

接着上一篇文章USB学习(1)&#xff1a;USB基础之接口类型、协议标准、引脚分布、架构、时序和数据格式&#xff0c;继续介绍一下USB的相关知识。 文章目录 1 USB端点(Endpoints)1.1 基本知识1.2 四种端点 2 传输协议2.1 数据包类型2.1.1 令牌数据包(Token packets)2.1.2 数据数…

【机器学习合集】激活函数合集 ->(个人学习记录笔记)

文章目录 综述1. S激活函数(sigmoid&Tanh)2. ReLU激活函数3. ReLU激活函数的改进4. 近似ReLU激活函数5. Maxout激活函数6. 自动搜索的激活函数Swish 综述 这些都是神经网络中常用的激活函数&#xff0c;它们在非线性变换方面有不同的特点。以下是这些激活函数的主要区别&am…

学习笔记二十三:Deployment入门到企业实战应用

Deployment入门到企业实战应用 Deployment控制器&#xff1a;概念、原理解读Deployment概述Deployment工作原理&#xff1a;如何管理rs和Pod&#xff1f;什么叫做更新节奏和更新逻辑呢 Deployment使用案例&#xff1a;创建一个web站点,2个副本deploy-demo详细解读 通过k8s实现滚…

分布式:一文搞定Redis/Zookeeper/MySQL实现分布式锁

目录 一、项目准备spring项目数据库 二、传统锁演示超卖现象使用JVM锁解决超卖解决方案JVM失效场景 使用一个SQL解决超卖使用mysql悲观锁解决超卖使用mysql乐观锁解决超卖四种锁比较Redis乐观锁集成Redis超卖现象redis乐观锁解决超卖 三、分布式锁概述四、Redis分布式锁实现方案…

Ubuntu 命令行设置静态IP地址方法

一、先ifconfig查看电脑的网卡信息 找到有线网络或WiFi网络的网卡名称&#xff0c;我这里是eno1 二、输入route -n命令&#xff0c;打印路由表&#xff0c;这里主要是为了查看网关地址 我这里网关地址是192.168.10.1 三、更改配置文件 输入 vim /etc/network/interfaces&am…

Spring Boot拦截器Interceptor

文章目录 Interceptor 作用原理自定义 InterceptorStep 1 实现/继承Step 2 重写方法Step 3 拦截器Interceptor注册例子 Interceptor 作用 日志记录&#xff1a;记录请求信息的日志&#xff0c;以便进行信息监控、信息统计、计算 PV&#xff08;Page View&#xff09;等&#x…

禾匠旧版对接微信小程序发货系统(发货信息管理 接口)

最近小程序如果是商家交易需要再小程序后台点击一下发货&#xff0c;特别麻烦&#xff0c;但是旧版的禾匠又没有这个功能&#xff0c;所以只能手动增加这个功能&#xff0c;但是每一个版本发货逻辑都不一样&#xff0c;大家只能自己手动去兼容一下&#xff0c;下面只是写了一个…