二叉搜索树(超详细+通俗易懂)

embedded/2024/10/18 8:19:51/

二叉搜索树定义:

二叉搜索树又被称为二叉排序树/二叉搜索树,为什么会被起这样的名字呢?我们先来看一张二叉搜索树的图片
在这里插入图片描述
这张图片里面的树就是二叉搜素树,那么二叉树有什么性质呢?我们从图中可以发现,每一个子树都是左节点<根节点<右节点,所以对于二叉搜索树的每一个节点来说,若它的左子树不为空,则它的左子树所有节点的值都小于根节点的值,若它的右子树不为空,则它的右子树所有节点的值都大于根节点的值。它的左右子树也满足二叉搜索树的性质。

二叉搜索树实现

1.创建和初始化:

我们看了上面二叉搜索树的图片后,我们知道二叉树需要有指向左右子树的结点,还有val值,初始化我们需要先把指向左右子树的指针指向空,再给个值。

//1.结点是公有的
template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;//构造函数BSTreeNode(const K& key):_left(nullptr): _right(nullptr): _key(key){};
};

2.插入(二叉搜索树插入结点时,不能破坏二叉搜索树的性质)

插入结点有两种情况:
1.二叉搜索树为空,插入的结点直接为根结点
在这里插入图片描述
2.二叉搜索树不为空,如果需要插入结点,那么需要先查找到需要插入的位置,再插入新结点。
在这里插入图片描述

template<class K>
class BSTree
{typedef BSTreeNode<K> Node;
public://二叉搜索树的插入bool Insert(const K& key){//如果树为空,就先new出一个新的结点//再把这个结点给根结点//返回trueif (_root == nullptr){_root = new Node(key);return true;}//如果树不为空//parent结点是为了寻找cur的父亲结点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;}//在需要插入的位置new出一个结点cur = new Node(key);//再把parent和cur结点链接起来//比较插入的值和根结点的值if (key > parent->_key)parent->_right = cur;elseparent->_left = cur;return true;}}
private://创建一个指向根结点的指针Node* _root = nullptr;
};

3.查找:

在这里插入图片描述

//二叉搜索树的查找
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;elsereturn true;}//找不到return false;
}

4.删除(二叉搜索树删除结点时,不能破坏二叉搜索树的性质)

如果需要删除的结点不在树中,那么就无需删除,如果需要删除的结点在树中,那么需要分为以下四种情况讨论
(1)没有左右结点的结点的删除(可以归类到左子树为空/右子树为空的情况)

(2)有左子节点没有右子节点的结点的删除
在这里插入图片描述

(3)有右子节点没有左子节点的结点的删除
在这里插入图片描述

(4)有左右结点的结点的删除

在这里插入图片描述

//4.二叉搜索树结点的删除
bool Erase(const K& key)
{Node* parent = nullptr;Node* cur = _root;//先查找需要删除的结点的位置while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//开始删除//1.当cur的右子结点为空if (cur->_left == nullptr){//如果是根结点//直接指向空if (cur == _root)_root = cur->_right;else{if (cur == parent->_left)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}//2.当cur的左子结点为空else if (cur->_left == nullptr){if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}}//3.当cur的左右结点不为空else{//有右子树的最小结点和根结点互换Node* rightMin = _root->_right;Node* rightMinParent = cur;//先找到右子树最小结点while (rightMin->_left){rightMinParent = rightMin;//不断往左寻找rightMin = rightMin->_left;}//覆盖掉根结点cur->_key = rightMin->_key;//删除rightMin结点//rightMin结点的右子结点可能不为空if (parent->_left = rightMin)parent->_left = rightMin->_right;elseparent->_right = rightMin->_right;//再删除掉rightMindelete rightMin;}return true;}}//找不到return false;
}

总结

#include <iostream>
using namespace std;
//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;
public://二叉搜索树的插入bool Insert(const K& key){//如果树为空,就先new出一个新的结点//再把这个结点给根结点//返回trueif (_root == nullptr){_root = new Node(key);return true;}//如果树不为空//parent结点是为了寻找cur的父亲结点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;}//在需要插入的位置new出一个结点cur = new Node(key);//再把parent和cur结点链接起来//比较插入的值和根结点的值if (key > parent->_key)parent->_right = cur;elseparent->_left = cur;return true;}}//二叉搜索树的查找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;elsereturn true;}//找不到return false;}//4.二叉搜索树结点的删除bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;//先查找需要删除的结点的位置while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//开始删除//1.当cur的右子结点为空if (cur->_left == nullptr){//如果是根结点//直接指向空if (cur == _root)_root = cur->_right;else{if (cur == parent->_left)parent->_left = cur->_left;elseparent->_right = cur->_left;}delete cur;}//2.当cur的左子结点为空else if (cur->_left == nullptr){if (cur == _root)_root = cur->_left;else{if (cur == parent->_right)parent->_right = cur->_right;elseparent->_left = cur->_right;}}//3.当cur的左右结点不为空else{//有右子树的最小结点和根结点互换Node* rightMin = _root->_right;Node* rightMinParent = cur;//先找到右子树最小结点while (rightMin->_left){rightMinParent = rightMin;//不断往左寻找rightMin = rightMin->_left;}//覆盖掉根结点cur->_key = rightMin->_key;//删除rightMin结点//rightMin结点的右子结点可能不为空if (parent->_left = rightMin)parent->_left = rightMin->_right;elseparent->_right = rightMin->_right;//再删除掉rightMindelete rightMin;}return true;}}//找不到return false;}
private://创建一个指向根结点的指针Node* _root = nullptr;
};

http://www.ppmy.cn/embedded/127788.html

相关文章

JavaSE——集合2:List(Iterator迭代器、增强for、普通for循环遍历集合)

目录 一、List (一)List接口基本介绍 二、List接口的常用方法 三、List集合的三种遍历方式 四、小练习——使用冒泡排序遍历集合 一、List (一)List接口基本介绍 List接口是Collection接口的子接口 public interface List<E> extends Collection<E> List集…

CMake函数:get_filename_component——从文件路径中提取特定组件

get_filename_component是CMake中的一个命令&#xff0c;用于从文件路径中提取特定组件&#xff08;例如目录、文件名、扩展名等&#xff09;。它的语法如下&#xff1a; get_filename_component(<VAR> <FileName> <COMP> [CACHE])其中&#xff1a; <VA…

Animatediff 工作流之神 Jerry Davos 新作! 使用Differential Diffusion使视频转绘生成稳定的背景。

今天给大家介绍一个新的ComfyUI工作流程&#xff0c;是Animatediff 工作流之神 Jerry Davos 新作。利用 Differential Diffusion 确保视频转绘的时候生成稳定的背景。 它可以使用蒙版对主体和背景进行不同的降噪值降噪&#xff0c;也可以设置它们的控制网为不同的强度。这样&a…

一种用于机械手自适应抓取控制的紧凑型指尖形视触觉传感器

背景 在机器人操作中&#xff0c;手部触觉感知对于稳定抓取起着重要作用。然而&#xff0c;传统的机械手多依赖于固定的抓力预设&#xff0c;无法灵活调整以适应不同类型的物体。尤其在处理脆弱、柔软或不规则物体时&#xff0c;预设的抓力可能导致物体损坏或抓取失败。为此&am…

国产化工业AI浪潮下,鸿道Intewell操作系统加速生产自动化向智能化转变

鸿道&#xff08;Intewell&#xff09;操作系统全面展示工业AI自主力量&#xff0c;加快生产自动化向智能化转变。 “将A处所有不同形状不同颜色的小方块移动到B处&#xff0c;并整齐堆叠。”工作人员对着眼前一台机械臂模样的工业机器人发出指令。短暂几秒后&#xff0c;“听懂…

STL.string(中)

string 迭代器findswapsubstrrfindfind_first_of&#xff08;用的很少&#xff09;find_last_of&#xff08;用的很少&#xff09;find_first_not_of&#xff08;用的很少&#xff09; 迭代器 int main() {//正向迭代器string s1("hello world!");string::iterator i…

自制简单的黄金投资预测脚本

github地址&#xff1a;https://github.com/CaLlMeErIC/GoldInvest 起因是在蚂蚁财富上有黄金ETF&#xff0c;就想着能不能写个脚本&#xff0c;通过读取历史黄金数据来给出一定的投资建议。 首先是数据来源&#xff0c;可以通过yfinance 来下载&#xff0c;不仅可以下载黄金数…

我常用的两个单例模式写法 (继承Mono和不继承Mono的)

不继承Mono 不继承Mono代表不用挂载到场景物体上面&#xff0c;因此直接饿汉式 加 合并空运算符判空创建实例 >(lambda表达式)的意思是get&#xff0c;就是将instance赋给Instance属性 //单例private static JsonDataManager instance new JsonDataManager();public stati…