震惊,搜索二叉树告诉我们不要生二胎?本篇(带图)让你轻松拿下

news2024/12/23 13:23:17

引子:

二叉树作为一种常见的一种数据结构,我们也经常使用,有以下几种类型:满二叉树(Full Binary Tree):所有节点都恰好有两个子节点或没有子节点。完全二叉树(Complete Binary Tree):如果一个二叉树的深度为h,除了最后一层外,所有层的节点数都是最大(即每个层都是满的),并且最后一层的节点尽可能地集中在左侧。平衡二叉树(Balanced Binary Tree):任何两个子树的高度差不超过1。二叉搜索树(Binary Search Tree, BST):对于每个节点,左子树上的所有节点的值都小于该节点的值,右子树上的所有节点的值都大于该节点的值,今天我们就来讲一讲搜索二叉树的实现!

set底层略介绍:

set 的底层实现通常依赖于哈希表(Hash Table)或平衡二叉搜索树(如红黑树)。以下是两种常见的实现方式

应用场景

  • 去重:快速检查元素是否已经存在于集合中。
  • 集合操作:执行并集、交集、差集等操作,常用于数据分析和统计。
  • 快速查找:在大量数据中快速定位元素

以下是cplusplus中的介绍:

 

故,与我们今天要讲的搜索二叉树有相通之处!

正文(基本思路与代码实现):

基本思路:

什么是二叉搜索树:

二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树,它具有以下性质:

  1. 有序性:对于树中的每个节点,其左子树上的所有节点的值都小于该节点的值,其右子树上的所有节点的值都大于该节点的值。
  2. 唯一性:树中没有重复的节点。

基本操作

  1. 插入(Insertion)

    • 从根节点开始,比较新节点的值与当前节点的值。
    • 如果新节点的值小于当前节点的值,则移动到当前节点的左子节点;否则,移动到右子节点。
    • 重复上述步骤,直到找到一个空的子节点位置,将新节点插入。
  2. 删除(Deletion)

    • 首先找到要删除的节点。
    • 如果该节点没有子节点,直接删除它。
    • 如果该节点只有一个子节点,删除该节点,并用其子节点替换它。
    • 如果该节点有两个子节点,找到其右子树的最小节点(或左子树的最大节点),将这个节点的值复制到要删除的节点,然后删除这个最小(或最大)节点。
  3. 搜索(Search)

    • 从根节点开始,比较要搜索的值与当前节点的值。
    • 如果值小于当前节点的值,则移动到左子节点;否则,移动到右子节点。
    • 重复上述步骤,直到找到目标值或到达空的子节点。

特点

  • 时间复杂度:在最坏的情况下(树退化为链表),插入、删除和搜索的时间复杂度为 O(n)。在最好的情况下(树完全平衡),这些操作的时间复杂度为 O(log n)。
  • 空间复杂度:O(n),其中 n 是树中节点的数量。

最坏情况:

应用

  • 数据存储和检索:由于其有序性,二叉搜索树常用于存储和检索数据。
  • 排序算法:如归并排序和快速排序中的分治策略。
  • 动态数据集:在需要频繁插入和删除数据的场景中,二叉搜索树是一个有效的数据结构。

变种

  • 平衡二叉搜索树(如AVL树):通过保持树的高度平衡,确保所有操作的时间复杂度为 O(log n)。
  • 红黑树:通过引入颜色标记和旋转操作,保持树的大致平衡,确保操作的时间复杂度为 O(log n)。

代码实现:

template<class T>
struct SBTreeNode  //默认是公有的
{
    T _key;
    SBTreeNode<T>* _left;
    SBTreeNode<T>* _right;

    SBTreeNode(const T& key)
        :_key(key)
        ,_left(nullptr)
        ,_right(nullptr)
    {}
};

template<class T>
class SBtree
{
    typedef SBTreeNode<T>  Node;
public:
    bool insert(const T& key)
    {
        //没有值就添加
        if (_root==nullptr)
        {
            _root = new Node(key);
            return true;
        }
        Node* parent = nullptr;
        Node* current = _root;

        while (current)
        {
            if (current->_key < key)
            {
                parent = current;
                current = current->_right;
            }
            else if (current->_key > key)
            {
                parent = current;
                current = current->_left;
            }
            else
            {
                return false;
            }
        }
        //新增节点再链接上去
        current = new Node(key);
        if (key > (parent->_key))
        {
            parent->_right = current;
        }
        else if (key < (parent->_key))
        {
            parent->_left = current;
        }
        return true;
    }

    bool find(const T&key)
    {
        Node* current = _root;
        while (current)
        {
            if (current->_key < key)
            {
                current = current->_right;
            }
            else if(current->_key>key)
            {
                current = current->_left;
            }
            else
            {
                return true;
            }
        }
        return false;
    }
    //中序有序,避免了_root是内部private的加密
    void _InOrder()
    {
        _InOrder(_root);
        printf("\n");
    }

删除有3种情况:

    bool Erase(const T& key)
    {
        //三种情况
        //一,没有娃
        //二,有二个娃
        //三,有二个及以上的娃
        //首先要找到这个数;
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key > key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else if (cur->_key < key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else
            {
                if (cur->_left == nullptr)
                {
                    if (parent == nullptr)
                        _root = cur->_right;
                    else
                    {
                        if (parent->_right == cur)
                            parent->_right = cur->_right;
                        else
                            parent->_left = cur->_right;
                    }
                    delete cur;
                    return true;
                }
                else if(cur->_right == nullptr)
                {
                    if (parent == nullptr)
                        _root = cur->_left;
                    else
                    {
                        if (parent->_right == cur)
                            parent->_right = cur->_left;
                        else
                            parent->_left = cur->_left;
                    }
                    delete cur;
                    return true;

                }
                //二个孩子的节点
                else
                {
                    Node* rightMinParent = cur;
                    Node* rightMin = cur->_right;
                    while (rightMin->_left)
                    {
                        rightMinParent = rightMin;
                        rightMin = rightMin->_left;
                    }

                    cur->_key = rightMin->_key;

                    if (rightMinParent->_left == rightMin)
                        rightMinParent->_left = rightMin->_right;
                    else
                        rightMinParent->_right = rightMin->_right;

                    delete rightMin;
                    return true;
                }
            }
        }
        return false;
    }
private:
    void _InOrder(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }
        //左根右;
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }

    //要赋予初始值
    Node* _root=nullptr;
};
int main()
{
    SBtree<int> high;
    int a[] = { 12,32,54,75,342,7567,2, 2};
    for (auto e : a)
    {
        high.insert(e);
    }
    high._InOrder();
    high.Erase(32);
    high._InOrder();
    high.Erase(75);
    high._InOrder();
    high.Erase(54);
    return 0;
}

"感谢您花时间阅读这篇文章。我希望它能给您带来一些有价值的见解和启发。如果您有任何想法或问题,请在评论区告诉我,我很乐意听到您的声音。别忘了点赞我的博客,哈哈哈!"

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

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

相关文章

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第三十六章 Linux驱动初探

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)

Python list comprehension {列表推导式 - 列表解析式 - 列表生成式} 1. Python list comprehension (列表推导式 - 列表解析式 - 列表生成式)2. Example3. ExampleReferences Python 中的列表解析式并不是用来解决全新的问题&#xff0c;只是为解决已有问题提供新的语法。 列…

易我数据恢复怎么样?这款四款也很好用

虽然我已经很小心了&#xff0c;但是生活中总有一些意外情况导致数据丢失&#xff0c;这时&#xff0c;数据恢复软件便成为了我们的救命稻草。不知道大家用过易我数据恢复没。我用过&#xff0c;但是目前更喜欢下面的四款数据恢复工具&#xff0c;更符合我的使用习惯&#xff0…

【ai】学习笔记:电影推荐1:协同过滤 TF-DF 余弦相似性

2020年之前都是用协同过滤2020年以后用深度学习、人工智能视频收费的,不完整,里面是电影推荐 这里有个视频讲解2016年大神分析了电影推荐 :MovieRecommendation github地址 看起来是基于用户的相似性和物品的相似性,向用户推荐物品: 大神的介绍: 大神的介绍: 基于Pytho…

Windows tasklist命令详解,Windows查看进程

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 tasklist 可以…

Chapter14 非真实感渲染 NPR——Shader入门精要

Chapter14 非真实感渲染 NPR 一、卡通风格渲染1.渲染轮廓线2.添加高光3.ToonShadingMat 二、素描风格渲染 一、卡通风格渲染 特点&#xff1a;物体被黑色线条描边&#xff0c;分明的明暗变化等方法&#xff1a;其中之一就是 基于色调的着色技术 1.渲染轮廓线 方法 基于观察角…

零基础入门鸿蒙开发 HarmonyOS NEXT星河版开发学习

今天开始带大家零基础入门鸿蒙开发&#xff0c;也就是你没有任何编程基础的情况下就可以跟着石头哥零基础学习鸿蒙开发。 目录 一&#xff0c;为什么要学习鸿蒙 1-1&#xff0c;鸿蒙介绍 1-2&#xff0c;为什么要学习鸿蒙 1-3&#xff0c;鸿蒙各个版本介绍 1-4&#xff0…

MYSQL2

1.建库以及建表&#xff1a; mysql> create database mydb8_woker; mysql> use mydb8_woker; mysql> create table t_worker( -> department_id int(11) not null comment 部门号, -> worker_id int(11) primary key not null comment 职工号, -&…

Java中的Heap(堆)(如果想知道Java中有关堆的知识点,那么只看这一篇就足够了!)

前言&#xff1a;&#xff08;Heap&#xff09;是一种特殊的完全二叉树&#xff0c;它在诸多算法中有着广泛的应用&#xff0c;本文将详细介绍Java中的堆。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 先让我们看一下本文大…

《Milvus Cloud向量数据库指南》——开源许可证的开放度:塑造AI开发合作与创新的双刃剑

在人工智能(AI)技术日新月异的今天,开源软件作为推动技术创新的重要力量,其许可证的开放度成为了影响AI开发合作、创新模式乃至整个行业生态的关键因素。不同的开源许可证模型,以其各自独特的开放程度,不仅决定了软件项目的可访问性和可定制性,还深刻影响着AI领域内的合…

springboot 实体类加注解校验入参数据

导入的是springboot自身的依赖包 import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid;

R语言进行K折交叉验证问题

在使用R语言进行模型参数评估优化时候&#xff0c;会使用K折交叉验证&#xff0c;其中会遇到各种各样问题&#xff1a; 错误: C5.0 models require a factor outcome > (1-mean(E0));(1-mean(E1)) [1] 1 [1] 1 报错说明C5.0模型需要因子变量输出&#xff0c;源代码如下&am…

还在为电脑录屏困扰吗?试试这4个方法,瞬间解决

现在很多人用手机进行日常操作都知道录屏的功能怎么操作&#xff0c;但是电脑录屏怎么录呢&#xff1f;如果你需要使用电脑进行录屏操作的时候就可以看看这篇文章。 1.福晰录屏大师 这个工具是一个专业的录屏软件。可以控制录制的区域范围&#xff0c;也能控制音频来源&#…

鸿蒙仓颉语言【匹配match】

模式匹配match match特性是现代编程语言中常见的特性&#xff0c;它们在不同的编程语言中有类似的概念和语法&#xff0c;但在细节上可能有一些差异。它们都可以提高代码的灵活性和可重用性&#xff0c;但用法和语法可能会因编程语言而异。 仓颉的match 支持通过箭头函数直接…

python用selenium网页模拟时xpath无法定位元素解决方法2

有时我们在使用python selenium xpath时&#xff0c;无法定位元素&#xff0c;红字显示no such element。上一篇文章写了1种情况&#xff0c;是包含iframe的&#xff0c;详见https://blog.csdn.net/Sixth5/article/details/140342929。 本篇写第2种情况&#xff0c;就是xpath定…

怎样对 PostgreSQL 中的慢查询进行分析和优化?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 怎样对 PostgreSQL 中的慢查询进行分析和优化&#xff1f;一、理解慢查询的危害二、找出慢查询&#x…

恶补,先验分布,后验分布 ,似然估计

恶补&#xff0c;打一遍增加印象 先验分布后验分布&#xff0c;似然估计 声明&#xff1a;仅记录个人学习&#xff0c;并无其他用途。 先验分布 后验分布&#xff0c; 似然估计 隔壁小哥的故事&#xff1a; 隔壁小哥要去15公里外的一个公园里玩&#xff0c;小哥可以选择步行…

使用 Elasticsearch 和 OpenAI 为你的客户成功应用程序构建对话式搜索

作者&#xff1a;来自 Elastic Lionel Palacin 在此博客中&#xff0c;我们将探讨如何通过利用大型语言模型 (LLM) 和检索增强生成 (RAG) 等技术实施对话式搜索来增强你的客户成功应用程序。 你将了解对话式搜索在客户成功应用程序环境中的优势&#xff0c;以及如何使用 Elast…

复制配置,多个端口号一起开启。

选择 输入&#xff1a;-Dserver.port8082

安卓原生聊天面板开发(一)整体规划

系列文章 安卓原生聊天面板开发&#xff08;一&#xff09;整体规划 安卓原生聊天面板开发&#xff08;二&#xff09;emoji功能实现 安卓原生聊天面板开发&#xff08;三&#xff09;录音交互实现 安卓原生聊天面板开发&#xff08;四&#xff09;整体交互实现 背景 产品喝…