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

news2025/4/27 15:38:19

  • 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)

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

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

相关文章

【C/C++】类之间的纵向关系——继承的概念

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

C++——继承(2)详解

目录 一.子类和父类对象的赋值转换 子类对象赋值父类对象的另外两种方式&#xff1a; 总结&#xff1a; 二.父类与子类的作用域 1. 在继承体系中基类和派生类都有独立的作用域。 例&#xff1a; 2.作用域练习 练习1&#xff1a; 解决方法: 一.子类和父类对象的赋值转换 …

深入理解Java类加载机制中的双亲委派模型--根据源码探讨

前言&#xff1a; 今天和大家探讨一道Java中经典的面试题&#xff0c;这道面试题经常出现在各个公司的面试中&#xff0c;本篇文章主要讲解ava类加载机制中的双亲委派模型的知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大…

Cesium态势标绘专题-三角旗标、矩形旗标、曲线旗标(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

前端JavaScript作用域详解

目录 前言 什么是作用域 作用域类型 全局作用域 局部作用域 块级作用域 ES6之前 ES6以后 作用域链 变量提升 基础概念 优先级问题 闭包 定义 特点 使用场景 封装私有变量 延长变量周期 模块化、命名空间 缓存 ES6的作用域 const、let 块级作用域 变量提…

tinymce4/5实现将word中内容(文字图片等)直接粘贴至编辑器中——利用插件tinymce-powerpaste-plugin

TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&#xff1a; 开源可商用&#xff0c;基于LGPL2.1 插件丰富&#xff0c;自带插件基本涵盖日常…

关于时序图

时序图 01 什么是时序图&#xff1f;02 时序图的组成元素2.1 对象2.2 生命线2.3 消息 03 如何绘制 01 什么是时序图&#xff1f; 时序图是UML交互图中的一类&#xff0c;又名序列图、顺序图。 用于描述对象之间的传递消息的时间顺序&#xff08;包括发送消息、接收消息、处理…

一个女程序员的成长之路

2013年大学毕业了&#xff0c;带着迷茫与好玩&#xff0c;我还年轻的心态&#xff0c;开始在郑州寻觅工作机会&#xff0c;最后很荣幸的在一家小公司入职了&#xff0c;工作的内容是给种植大棚的用户打电话&#xff0c;推销农药。每天就是在网上各种农业平台上面找号码&#xf…

ASIC-WORLD Verilog(11)过程时序控制

写在前面 在自己准备写一些简单的verilog教程之前&#xff0c;参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好&#xff0c;奈何没有中文&#xff0c;在下只好斗胆翻译过来&#xff08;加了自己的理解&#xff09;分享给大家。 这是网站原文&…

【vue】vue中Mixins的用法(jeecg-boot为例):

文章目录 一、jeecg-boot本身只有JeecgListMixin.js二、使用Mixin:三、mixins详解&#xff1a;【1】由于每个项目的接口和参数不同>这里引进js进行处理&#xff0c;不在Mixin里面处理了&#xff08;Mixin只做公共数据处理&#xff09;【2】公共的页面字典【3】解决方法里面不…

2009年上半年 软件设计师 上午试卷3

●下图属于UML 中的&#xff08;46),其中&#xff0c;AccountManagement 需要&#xff08;47)。 (46)A.组件图 B.部署图 C.类图 D.对象图 (47)A.实现 IdentityVerifier 接口并被 CreditCardServices 调用 B.调用 CreditCardServices 实现的 Identity Verifier 接口 C.实现 I…

设计模式大白话——装饰者模式

装饰者模式 文章目录 装饰者模式一、概述二、应用场景三、代码示例四、小结 一、概述 ​ 装饰者模式&#xff0c;此模式最核心之处在于装饰二字&#xff0c;之所以需要装饰&#xff0c;是因为基础的功能无法满足需求&#xff0c;并且装饰是临时的&#xff0c;并不是永久的&…

基于Java+spring+springMvc+mybatis+jsp学生选课管理系统

基于JavaspringspringMvcmybatisjsp学生选课管理系统 一、系统介绍二、功能展示1.课程列表(学生)2.已选课程(学生)3.已修课程(学生)4.我的课程&#xff08;老师&#xff09;5.课程打分&#xff08;老师&#xff09;6.课程管理、学生管理、教师管理&#xff08;系统管理员&#…

python字典:怎么取出key对应的值

目录 python中的字典是什么 怎么判断key是否在字典中 怎么取出key对应的值 总结 python中的字典是什么 在Python中&#xff0c;字典&#xff08;Dictionary&#xff09;是一种无序且可变的数据类型&#xff0c;用于存储键-值&#xff08;Key-Value&#xff09;对。字典通过…

电脑卡顿反应慢怎么处理?提升反应速度的方法

电脑卡顿反应慢是很常见的问题&#xff0c;然而&#xff0c;我们可以采取一些方法来处理这个问题&#xff0c;帮助大家提升电脑反应速度。​ 一、提升电脑反应速度的方法 当电脑运行顺畅时&#xff0c;我们的工作体验也会更加愉悦。然而&#xff0c;如果电脑出现卡顿反应慢的…

【项目设计】MySQL 连接池的设计

目录 &#x1f449;关键技术点&#x1f448;&#x1f449;项目背景&#x1f448;&#x1f449;连接池功能点介绍&#x1f448;&#x1f449;MySQL Server 参数介绍&#x1f448;&#x1f449;功能实现设计&#x1f448;&#x1f449;开发平台选型&#x1f448;&#x1f449;MyS…

【雕爷学编程】MicroPython动手做(24)——掌控板之拓展掌控宝

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

【雕爷学编程】MicroPython动手做(23)——掌控板之WiFi与蓝牙2

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

1400*D. Candy Box (easy version)(贪心)

3 10 9 Example input 3 8 1 4 8 4 5 6 3 8 16 2 1 3 3 4 3 4 4 1 3 2 2 2 4 1 1 9 2 2 4 4 4 7 7 7 7 output 题意&#xff1a; n个糖果&#xff0c;分为多个种类&#xff0c;要求尽可能的多选&#xff0c;并且使得不同种类的数量不能相同。 解析&#xff1a; 记录每种糖…

音视频技术开发周刊 | 304

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 更强的Llama 2开源&#xff0c;可直接商用&#xff1a;一夜之间&#xff0c;大模型格局变了 Meta 终于发布了大家期待已久的免费可商用版本 Llama 2。 6000份问卷透露出AI…