【高级程序设计语言C++】二叉搜索树

  • 1. 二叉搜索树的概念
  • 2. 二叉搜索树的功能
    • 2.1. 二叉搜索树的简单模型
    • 2.2. 二叉搜索树的查找
    • 2.3. 二叉搜索树的插入
    • 2.4. 二叉搜索树的删除
  • 3. 二叉搜索树的性能分析

1. 二叉搜索树的概念

二叉搜索树(Binary Search Tree,简称BST)是一种常见的二叉树数据结构,它具有以下特点:

  1. 每个节点最多有两个子节点,分别称为左子节点和右子节点。
  2. 对于任意节点,其左子树中的所有节点的值都小于该节点的值,而其右子树中的所有节点的值都大于该节点的值。
  3. 对于任意节点,其左子树和右子树也分别是二叉搜索树。

这些特性使得二叉搜索树在查找、插入和删除等操作上具有高效性。

简单的二叉搜索树如下图:

img

2. 二叉搜索树的功能

2.1. 二叉搜索树的简单模型

template<class K, class V>
struct BSTreeNode
{
	BSTreeNode(K key, V value)
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
		,_value(value)
	{}
	BSTreeNode* _left;
	BSTreeNode* _right;
	K _key;
	V _value;
};
template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	bool Insert(const K& key, const V& value)
	{}
	Node* Find(const K& key)
	{}
	bool Erase(const K& key)
	{}
	void _InOrder(Node* root)
	{}
	void InOrder()
	{}
private:
	Node* _root = nullptr;
};

2.2. 二叉搜索树的查找

对于二叉搜索树的查找操作,可以通过以下步骤实现:

  1. 从根节点开始,比较要查找的值与当前节点的值。
  2. 如果要查找的值等于当前节点的值,则找到了目标节点。
  3. 如果要查找的值小于当前节点的值,则继续在当前节点的左子树中查找。
  4. 如果要查找的值大于当前节点的值,则继续在当前节点的右子树中查找。
  5. 如果在某个节点为nullptr时仍然没有找到目标节点,则说明目标节点不存在于二叉搜索树中。
Node* 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 cur;
        }
    }
    return nullptr;
}

2.3. 二叉搜索树的插入

对于二叉搜索树的插入操作,可以通过以下步骤实现:

  1. 从根节点开始,比较要插入的值与当前节点的值。
  2. 如果要插入的值小于当前节点的值,并且当前节点的左子节点为nullptr,则将新节点插入为当前节点的左子节点。
  3. 如果要插入的值大于当前节点的值,并且当前节点的右子节点为nullptr,则将新节点插入为当前节点的右子节点。
  4. 如果要插入的值与当前节点的值相等,则不进行插入操作(可以根据需求进行处理)。
  5. 如果要插入的值与当前节点的值不相等,并且当前节点的左子节点或右子节点不为空,则将当前节点更新为其左子节点或右子节点,然后回到第2步继续比较。
bool Insert(const K& key, const V& value)
{
    Node* cur = _root;
    Node* parent = _root;
    if (cur == nullptr)
    {
        _root = new Node(key, value);
        return true;
    }
    while (cur)
    {
        if (key > cur->_key)
        {
            parent = cur;
            cur = cur->_right;
        }
        else if (key < cur->_key)
        {
            parent = cur;
            cur = cur->_left;
        }
        else
        {
            return false;
        }
    }
    if (key > parent->_key)
    {
        parent->_right = new Node(key, value);
        return true;
    }
    else if (key < parent->_key)
    {
        parent->_left = new Node(key, value);
        return true;
    }
    else
    {
        parent = new Node(key, value);
        return true;
    }
}

2.4. 二叉搜索树的删除

二叉搜索树的删除操作是一个相对复杂的过程,需要根据被删除节点的子节点情况进行不同的处理。下面是二叉搜索树删除操作的一般步骤:

  1. 首先,从根节点开始,比较要删除的值与当前节点的值。
  2. 如果要删除的值小于当前节点的值,则继续在当前节点的左子树中查找要删除的节点。
  3. 如果要删除的值大于当前节点的值,则继续在当前节点的右子树中查找要删除的节点。
  4. 如果找到了要删除的节点,需要根据其子节点情况进行不同的处理。

根据被删除节点的子节点情况,可以分为以下三种情况:

  • 情况一:被删除节点没有子节点(即为叶子节点)。

    • 直接删除该节点即可。
  • 情况二:被删除节点只有一个子节点。

    • 将该子节点替代被删除节点的位置。
  • 情况三:被删除节点有两个子节点。

    • 找到被删除节点的右子树中的最小节点(即右子树中最左下方的节点),将其值复制到被删除节点。
    • 然后,递归地删除右子树中的最小节点。

下面的示例代码,演示了如何在二叉搜索树种删除节点:

bool Erase(const K& key)
{
    Node* cur = _root;
    Node* parent = _root;
    while (cur)
    {
        if (key > cur->_key)
        {
            parent = cur;
            cur = cur->_right;
        }
        else if (key < cur->_key)
        {
            parent = cur;
            cur = cur->_left;
        }
        //找到删除的节点
        else
        {
            //如果是叶子节点
            if (cur->_left == nullptr && cur->_right == nullptr)
            {
                if (cur == _root)
                {
                    delete cur;
                    _root = nullptr;
                    return true;
                }
                if (cur == parent->_left)
                {
                    parent->_left = cur->_left;
                }
                else if (cur == parent->_right)
                {
                    parent->_right = cur->_left;
                }
                delete cur;
                cur = nullptr;
                return true;
            }
            //如果左右节点都不为空
            else if(cur->_left != nullptr && cur->_right != nullptr)
            {
                Node* minRight = cur->_right;
                Node* par = cur;
                if (minRight == nullptr)
                {
                    _root = cur->_left;
                    delete par;
                    par = nullptr;
                    return true;
                }
                //找右树的最小值,替换删除的节点
                while (minRight->_left)
                {
                    par = minRight;
                    minRight = minRight->_left;
                }
                swap(minRight->_key, cur->_key);
                swap(minRight->_value, cur->_value);
                if (minRight == par->_left)
                {
                    par->_left = minRight->_right;
                }
                else if (minRight == par->_right)
                {
                    par->_right = minRight->_right;
                }
                delete minRight;
                minRight = nullptr;
                return true;
            }
            //如果右节点为空
            else if (cur->_left)
            {
                if (cur == parent->_left)
                {
                    parent->_left = cur->_left;
                }
                else if (cur == parent->_right)
                {
                    parent->_right = cur->_left;
                }
                delete cur;
                cur = nullptr;
                return true;
            }
            //如果左节点为空
            else if (cur->_right)
            {
                if (cur == parent->_left)
                {
                    parent->_left = cur->_right;
                }
                else if (cur == parent->_right)
                {
                    parent->_right = cur->_right;
                }
                delete cur;
                cur = nullptr;
                return true;
            }
        }
    }
    return false;
}

3. 二叉搜索树的性能分析

二叉搜索树的性能取决于树的平衡性。

**如果二叉搜索树是平衡的,即左右子树的高度差不超过1,那么查找、插入和删除操作的平均时间复杂度将是O(log n)。**这是因为在平衡的二叉搜索树中,每一次操作都可以将搜索范围缩小一半,使得树的高度保持在较小的范围内。

然而,**如果二叉搜索树是不平衡的,即左右子树的高度差较大,那么查找、插入和删除操作的最坏时间复杂度将是O(n)。**这是因为在不平衡的二叉搜索树中,树的高度可能接近于节点数量,导致操作的效率大大降低。

为了解决二叉搜索树的不平衡问题,出现了一些平衡二叉搜索树的变种,比如AVL树、红黑树、B树等。这些树结构通过在插入和删除操作时进行平衡调整,使得树的高度保持在较小的范围内,从而提高了查找、插入和删除操作的性能。

**总结起来,二叉搜索树的性能取决于树的平衡性。在平衡的情况下,二叉搜索树可以提供快速的查找、插入和删除操作,平均时间复杂度为O(log n)。但是,如果树不平衡,性能会下降,最坏时间复杂度为O(n)。**因此,在实际应用中,选择合适的平衡二叉搜索树实现,或者采用其他高效的数据结构,是保证性能的重要考虑因素。

如下图:

img

查找的时间复杂度为O(log n),但是如果下面的二叉搜索树

img

查找的时间复杂度将会达到O(n)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# Onnx Paddle模型 OCR识别服务

效果 项目 可运行程序exe下载 Demo&#xff08;完整源码&#xff09;下载

03 制作Ubuntu启动盘

1 软碟通 我是用软碟通制作启动盘。安装软碟通时一定要把虚拟光驱给勾选上&#xff0c;其余两个可以看你心情。 2 镜像文件 我使用清华镜像网站找到的Ubuntu镜像文件。 Index of /ubuntu-releases/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 请自己选择镜像…

探索 GPTCache|GPT-4 将开启多模态 AI 时代,GPTCache + Milvus 带来省钱秘籍

世界正处于数字化的浪潮中&#xff0c;为了更好理解和分析大量数据&#xff0c;人们对于人工智能&#xff08;AI&#xff09;解决方案的需求呈爆炸式增长。 此前&#xff0c;OpenAI 推出基于 GPT-3.5 模型的智能对话机器人 ChatGPT&#xff0c;在自然语言处理&#xff08;NLP&a…

Word导出高清PDF

通过word导出pdf清晰度较高的方法_word如何导出高分辨率pdf_Perishell的博客-CSDN博客通过打印机属性设置&#xff0c;让word打印出比较高清的pdf_word如何导出高分辨率pdfhttps://blog.csdn.net/weixin_45390670/article/details/129228568?ops_request_misc%257B%2522reques…

卡片的点击事件通过点击进行路由传参

下面是详情页 通过 接收 <template><div class"detail"><img :src"row.imgUrl"><van-icon name"arrow-left" click"back" /></div> </template><script> export default {created() {let …

2023年第四届“华数杯”数学建模思路 - 案例:随机森林

## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 什么是随机森林&#xff1f; 随机森林属于 集成学习 中的 Bagging&#xff08;Bootstrap AGgregation 的简称&#xff09; 方法。如果用图来表示他们之…

喜报 | 《中国AIOps现状调查报告(2023)》发布!擎创科技案例再度入选

&#xff08;本文部分内容来自《中国AIOps现状调查报告&#xff08;2023&#xff09;》&#xff0c;丝小编扣1&#xff0c;领取完整版报告&#xff09; 2023年7月18日&#xff0c;信通院Xops产业创新发展论坛于北京成功举办。大会旨在提高企业研发运营水平&#xff0c;加强XOp…

【Linux】进程间通信——管道

目录 写在前面的话 什么是进程间通信 为什么要进行进程间通信 进程间通信的本质理解 进程间通信的方式 管道 System V IPC POSIX IPC 管道 什么是管道 匿名管道 什么是匿名管道 匿名管道通信的原理 pipe()的使用 匿名管道通信的特点 拓展代码 命名管道 什么是命…

问题:idea启动项目错误提示【command line is too long. shorten command line】

问题&#xff1a;idea启动项目错误提示【command line is too long. shorten command line】 参考博客 问题描述 启动参数过长&#xff0c;启动项目&#xff0c;错误提示 原因分析 出现此问题的直接原因是&#xff1a;IDEA集成开发环境运行你的“源码”的时候&#xff08…

java:解决报错非法字符: ‘\ufeff‘以及什么是BOM

背景 运行 JAVA 项目后&#xff0c;报错提示&#xff1a;非法字符: \ufeff&#xff0c;如图&#xff1a; 但是我在这个报错的文件中并没有搜到这个字符&#xff0c;那到底是什么原因 什么是BOM BOM&#xff08;Byte Order Mark&#xff09;&#xff0c;隐藏字符&#xff0c…

Pytorch深度学习-----神经网络之线性层用法

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用&#xff08;ToTensor&#xff0c;Normalize&#xff0c;Resize &#xff0c;Co…

python与深度学习(十一):CNN和猫狗大战

目录 1. 说明2. 猫狗大战2.1 导入相关库2.2 建立模型2.3 模型编译2.4 数据生成器2.5 模型训练2.6 模型保存2.7 模型训练结果的可视化 3. 猫狗大战的CNN模型可视化结果图4. 完整代码5. 猫狗大战的迁移学习 1. 说明 本篇文章是CNN的另外一个例子&#xff0c;猫狗大战&#xff0c…

Go -- 测试 and 项目实战

没有后端基础&#xff0c;学起来真是费劲&#xff0c;所以打算速刷一下&#xff0c;代码跟着敲一遍&#xff0c;有个印象&#xff0c;大项目肯定也做不了了&#xff0c;先把该学的学了&#xff0c;有空就跟点单体项目&#xff0c;还有该看的书.... 目录 &#x1f34c;单元测试…

realsense-viewer 不识别 T265——Realsense SDK 在 v2.54.1 版本以后不再支持T265相机的解决办法

由于T265停产&#xff0c;Intel RealSense™ SDK 2.0 (v2.54.1) 在该版本中移除了对T265相机的支持&#xff0c;以后的版本也不会支持了。为了继续使用 T265 相机&#xff0c;最好千万不要升级 realsense 相关的 package&#xff0c;但是还有新装机的需求啊。经测试Intel RealS…

深度学习Redis(4):哨兵

前言 在 Redis&#xff08;3&#xff09;&#xff1a;主从复制 中曾提到&#xff0c;Redis主从复制的作用有数据热备、负载均衡、故障恢复等&#xff1b;但主从复制存在的一个问题是故障恢复无法自动化。本文将要介绍的哨兵&#xff0c;它基于Redis主从复制&#xff0c;主要作…

js中exec与match的区别

const regex1 RegExp(f(o.?),g); const str1 table foatball, fobsball; let array1; let array2; array1 regex1.exec(str1) array2 str1.match(regex1)console.log(array1, array1); console.log(array2, array2); //没有g的情况下,都是找到第一个匹配,并且如果有分组,…

【C#学习笔记】引用类型(1)

文章目录 引用类型class匿名类 记录引用相等和值相等record声明 接口delegate 委托合并委托/多路广播委托 引用类型 引用类型的变量存储对其数据&#xff08;对象&#xff09;的引用&#xff0c;而值类型的变量直接包含其数据。 对于引用类型&#xff0c;两种变量可引用同一对…

软件开发和测试开发选哪个更好?一文讲清!

1、岗位需求分析 随着科技的发展&#xff0c;软件测试领域对人才的要求越来越高&#xff0c;特别测试开发岗位已成行业热点关注对象。 做开发的同学也对测试开发岗位感到好奇&#xff0c;为什么做测试还要写代码做开发&#xff1f; 他们都在开发些什么软件&#xff1f; 到底…

【C++】开源:Eigen3矩阵与线性代数库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Eigen3矩阵与线性代数库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…